2 Copyright 2013 Daniel Wirtz <dcode@dcode.io>
\r
4 Licensed under the Apache License, Version 2.0 (the "License");
\r
5 you may not use this file except in compliance with the License.
\r
6 You may obtain a copy of the License at
\r
8 http://www.apache.org/licenses/LICENSE-2.0
\r
10 Unless required by applicable law or agreed to in writing, software
\r
11 distributed under the License is distributed on an "AS IS" BASIS,
\r
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 See the License for the specific language governing permissions and
\r
14 limitations under the License.
\r
18 * ProtoBuf.js Test Suite.
\r
19 * @author Daniel Wirtz <dcode@dcode.io>
\r
23 var FILE = "protobuf.js";
\r
24 var BROWSER = !!global.window;
\r
25 var StdOutFixture = require('fixture-stdout');
\r
26 var fixture = new StdOutFixture();
\r
28 var ProtoBuf = BROWSER ? global.dcodeIO.ProtoBuf : require(__dirname+"/../dist/"+FILE),
\r
29 ByteBuffer = BROWSER ? global.dcodeIO.ByteBuffer : ByteBuffer || require("bytebuffer"),
\r
30 util = BROWSER ? null : require("util"),
\r
31 fs = BROWSER ? null : require("fs");
\r
33 if (typeof __dirname == 'undefined') {
\r
34 __dirname = document.location.href.replace(/[\/\\][^\/\\]*$/, "");
\r
38 * Constructs a new Sandbox for module loaders and shim testing.
\r
39 * @param {Object.<string,*>} properties Additional properties to set
\r
42 var Sandbox = function(properties) {
\r
43 this.ByteBuffer = function() {};
\r
44 for (var i in properties) {
\r
45 this[i] = properties[i];
\r
59 * Validates the complexDotProto and complexInline tests.
\r
60 * @param {*} test Nodeunit test
\r
61 * @param {Object} Game Game namespace
\r
63 function validateComplex(test, Game) {
\r
64 var Car = Game.Cars.Car,
\r
65 Vendor = Car.Vendor,
\r
69 // Car from class with argument list properties
\r
72 // Vendor from class with object properties
\r
73 vendor = new Vendor({
\r
74 "name": "Iron Inc.",
\r
75 // Address from object
\r
81 // Speed from enum object
\r
84 test.equal(car.model, "Rusty");
\r
85 test.equal(car.vendor.name, "Iron Inc.");
\r
86 test.equal(car.vendor.address.country, "US");
\r
87 test.equal(car.vendor.address.country, car.getVendor().get_address().country);
\r
88 var bb = new ByteBuffer(32);
\r
90 test.equal(bb.flip().toString("debug"), "<0A 05 52 75 73 74 79 12 15 0A 09 49 72 6F 6E 20 49 6E 63 2E 12 04 0A 02 55 53 1A 02 6D 31 18 02>");
\r
91 var carDec = Car.decode(bb);
\r
92 test.equal(carDec.model, "Rusty");
\r
93 test.equal(carDec.vendor.name, "Iron Inc.");
\r
94 test.equal(carDec.vendor.address.country, "US");
\r
95 test.equal(carDec.vendor.address.country, carDec.getVendor().get_address().country);
\r
96 test.equal(carDec.vendor.models[0], "m1");
\r
101 * @type {Object.<string,function>}
\r
105 "init": function(test) {
\r
106 test.ok(typeof ProtoBuf == "object");
\r
107 test.ok(typeof ProtoBuf.Reflect == 'object');
\r
108 test.ok(typeof ProtoBuf.loadProto == "function");
\r
109 test.ok(typeof ProtoBuf.loadProtoFile == "function");
\r
110 test.strictEqual(ProtoBuf.loadProto, ProtoBuf.protoFromString);
\r
111 test.strictEqual(ProtoBuf.loadProtoFile, ProtoBuf.protoFromFile);
\r
112 test.ok(ProtoBuf.ByteBuffer);
\r
116 "IS_NODE": function(test) {
\r
117 test.ok(ProtoBuf.Util.IS_NODE);
\r
121 // Example "A Simple Message" from the protobuf docs
\r
122 // https://developers.google.com/protocol-buffers/docs/encoding#simple
\r
123 "example1": function(test) {
\r
125 var builder = ProtoBuf.loadProtoFile(__dirname+"/example1.proto");
\r
126 var Test1 = builder.build("Test1");
\r
127 test.ok(typeof Test1 == 'function');
\r
128 var inst = new Test1(150);
\r
129 test.ok(inst instanceof ProtoBuf.Builder.Message);
\r
130 test.equal(inst.a, 150);
\r
131 test.equal(inst.getA(), 150);
\r
132 test.equal(inst.get_a(), 150);
\r
134 test.equal(inst.a, 151);
\r
135 test.equal(inst.getA(), 151);
\r
136 test.equal(inst.get_a(), 151);
\r
138 test.equal(inst.a, 152);
\r
139 test.equal(inst.toString(), ".Test1");
\r
140 test.throws(function() {
\r
141 inst.setA(null); // required
\r
143 test.throws(function() {
\r
146 var size = inst.calculate();
\r
147 var bb = new ByteBuffer(3);
\r
149 test.strictEqual(bb.offset, size);
\r
150 test.equal(bb.flip().toString("debug"), "<08 98 01>");
\r
151 var instDec = Test1.decode(bb);
\r
152 test.equal(instDec.a, 152);
\r
160 // Basically the same as example1, but with an unsigned value.
\r
161 "example1u": function(test) {
\r
163 var builder = ProtoBuf.loadProtoFile(__dirname+"/example1u.proto");
\r
164 var Test1u = builder.build("Test1u");
\r
165 test.ok(typeof Test1u == 'function');
\r
166 var inst = new Test1u(-1);
\r
167 test.strictEqual(inst.a, 4294967295);
\r
168 var bb = new ByteBuffer(6);
\r
169 var size = inst.calculate();
\r
171 test.strictEqual(bb.offset, size);
\r
172 test.equal(bb.flip().toString("debug"), "<08 FF FF FF FF 0F>");
\r
173 var instDec = Test1u.decode(bb);
\r
174 test.strictEqual(instDec.a, 4294967295);
\r
182 // Example "Strings" from the protobuf docs
\r
183 // https://developers.google.com/protocol-buffers/docs/encoding#types
\r
184 "example2": function(test) {
\r
186 var builder = ProtoBuf.loadProtoFile(__dirname+"/example2.proto");
\r
187 var Test2 = builder.build("Test2");
\r
188 var inst = new Test2("testing");
\r
189 var bb = new ByteBuffer(9);
\r
190 var size = inst.calculate();
\r
192 test.strictEqual(bb.offset, size);
\r
193 test.equal(bb.flip().toString("debug"), "<12 07 74 65 73 74 69 6E 67>");
\r
194 var instDec = Test2.decode(bb);
\r
195 test.equal(instDec.b, "testing");
\r
202 // Example "Embedded Messages" from the protobuf docs
\r
203 // https://developers.google.com/protocol-buffers/docs/encoding#embedded
\r
204 "example3": function(test) {
\r
206 var builder = ProtoBuf.loadProtoFile(__dirname+"/example3.proto");
\r
207 var root = builder.build();
\r
208 var Test1 = root.Test1;
\r
209 var Test3 = root.Test3;
\r
210 var inst = new Test3(new Test1(150));
\r
211 var bb = new ByteBuffer(5);
\r
212 test.equal(inst.c.a, 150);
\r
213 var size = inst.calculate();
\r
215 test.strictEqual(bb.offset, size);
\r
216 test.equal(bb.flip().toString("debug"), "<1A 03 08 96 01>");
\r
217 var instDec = Test3.decode(bb);
\r
218 test.equal(instDec.c.a, 150);
\r
225 "example4": function(test) {
\r
227 var builder = ProtoBuf.loadProtoFile(__dirname+"/example4.proto");
\r
228 var Test4 = builder.build("Test4");
\r
229 var inst = new Test4([3, 270, 86942]);
\r
230 var bb = new ByteBuffer(8);
\r
231 test.equal(inst.d.length, 3);
\r
232 var size = inst.calculate();
\r
234 test.strictEqual(bb.offset, size);
\r
235 test.equal(bb.flip().toString("debug"), "<22 06 03 8E 02 9E A7 05>");
\r
236 var instDec = Test4.decode(bb);
\r
237 test.equal(bb.toString("debug"), "22 06 03 8E 02 9E A7 05|");
\r
238 test.equal(instDec.d.length, 3);
\r
239 test.equal(instDec.d[2], 86942);
\r
246 "example5": function(test) {
\r
248 var builder = ProtoBuf.loadProtoFile(__dirname+"/example5.proto");
\r
256 "constructor": function(test) {
\r
257 var builder = ProtoBuf.loadProtoFile(__dirname+"/example1.proto");
\r
258 var Test1 = builder.build("Test1");
\r
259 var t1 = new Test1(123),
\r
260 t2 = new Test1({a: 123}),
\r
261 t3 = new Test1(t1);
\r
262 test.deepEqual(t1, t2);
\r
263 test.deepEqual(t2, t3);
\r
267 "constructorWithOneofs": function(test) {
\r
269 var builder = ProtoBuf.loadProtoFile(__dirname+"/oneof.proto"),
\r
270 MyOneOf = builder.build("MyOneOf"),
\r
271 TOneOf = builder.lookup(".MyOneOf");
\r
272 test.ok(TOneOf.getChild("my_oneof"));
\r
274 var myOneOf = new MyOneOf();
\r
275 test.strictEqual(myOneOf.my_oneof, null);
\r
276 myOneOf.set("id", 1);
\r
277 test.strictEqual(myOneOf.my_oneof, "id");
\r
278 myOneOf.set("name", "me");
\r
279 test.strictEqual(myOneOf.my_oneof, "name");
\r
280 test.strictEqual(myOneOf.id, null);
\r
282 var copy = new MyOneOf(myOneOf); // this line is what was failing
\r
283 // Error: .MyOneOf#my_oneof is not a field: undefined
\r
285 test.deepEqual(myOneOf, copy);
\r
287 // Test same things are there
\r
288 test.strictEqual(copy.my_oneof, "name");
\r
289 test.strictEqual(copy.name, "me");
\r
290 test.strictEqual(copy.id, null);
\r
297 "numberFormats": function(test) {
\r
299 var builder = ProtoBuf.loadProtoFile(__dirname+"/numberformats.proto");
\r
300 var Formats = builder.build("Formats");
\r
301 test.strictEqual(Formats.DEC, 1);
\r
302 test.strictEqual(Formats.HEX, 31);
\r
303 test.strictEqual(Formats.OCT, 15);
\r
304 var Msg = builder.build("Msg");
\r
305 var msg = new Msg();
\r
306 test.strictEqual(msg.dec, -1);
\r
307 test.strictEqual(msg.hex, -31);
\r
308 test.strictEqual(msg.hexUC, 521);
\r
309 test.strictEqual(msg.oct, -15);
\r
310 test.strictEqual(msg.exp, 0.1e5);
\r
311 test.strictEqual(msg.nod, 1.);
\r
312 test.strictEqual(msg.exn, 1e8);
\r
313 test.strictEqual(msg.sp1, Infinity);
\r
314 test.strictEqual(msg.sp2, -Infinity);
\r
315 test.ok(isNaN(msg.sp3));
\r
322 // Check encode/decode against a table of known correct pairs.
\r
323 // Note that javascript ArrayBuffer does not support signed Zero or NaN
\r
324 // bertdouglas (https://github.com/bertdouglas)
\r
325 "float": function(test) {
\r
327 var str_proto = "message Float {"
\r
328 + " required float f = 1;"
\r
330 var builder = ProtoBuf.loadProto(str_proto);
\r
331 var root = builder.build();
\r
332 var Float = root.Float;
\r
334 var in_tolerance = function (reference,actual) {
\r
337 if (reference != 0.0 ) {
\r
340 var err = Math.abs(reference - actual)/scale;
\r
345 // hex values are shown here in big-endian following IEEE754 notation
\r
346 // protobuf is little-endian
\r
347 // { f: -0.0 , b: "80 00 00 00" },
\r
348 { f: +0.0 , b: "00 00 00 00" },
\r
349 { f: -1e-10 , b: "AE DB E6 FF" },
\r
350 { f: +1e-10 , b: "2E DB E6 FF" },
\r
351 { f: -2e+10 , b: "D0 95 02 F9" },
\r
352 { f: +2e+10 , b: "50 95 02 F9" },
\r
353 { f: -3e-30 , b: "8E 73 63 90" },
\r
354 { f: +3e-30 , b: "0E 73 63 90" },
\r
355 { f: -4e+30 , b: "F2 49 F2 CA" },
\r
356 { f: +4e+30 , b: "72 49 F2 CA" },
\r
357 { f: -123456789.0 , b: "CC EB 79 A3" },
\r
358 { f: +123456789.0 , b: "4C EB 79 A3" },
\r
359 { f: -0.987654321 , b: "BF 7C D6 EA" },
\r
360 { f: +0.987654321 , b: "3F 7C D6 EA" },
\r
361 { f: -Infinity , b: "FF 80 00 00" },
\r
362 { f: +Infinity , b: "7F 80 00 00" }
\r
363 // { f: -NaN , b: "FF C0 00 00>" },
\r
364 // { f: +NaN , b: "7F C0 00 00" }
\r
367 f_vals.map( function(x) {
\r
369 var m1 = new Float();
\r
370 var b1 = new ByteBuffer();
\r
373 var q1 = b1.slice(1,5).compact().reverse();
\r
374 test.strictEqual('<' + x.b + '>', q1.toString("debug"));
\r
377 var b2 = new ByteBuffer();
\r
378 var s1 = x.b + ' 0D';
\r
379 var s2 = s1.split(" ");
\r
380 var s3 = s2.reverse();
\r
381 var i1 = s3.map(function(y) { return parseInt(y,16) } );
\r
382 i1.map(function(y) { b2.writeUint8(y) });
\r
383 b2.limit = b2.offset;
\r
385 var m2 = Float.decode(b2);
\r
387 var s4 = "" + x.f +" " + m2.f;
\r
388 if ( isNaN(x.f) ) {
\r
389 test.ok( isNaN(m2.f), s4 );
\r
391 else if ( ! isFinite( x.f) ) {
\r
392 test.ok( x.f === m2.f, s4 );
\r
395 test.ok( in_tolerance(x.f, m2.f), s4 );
\r
404 "bytes": function(test) {
\r
406 var str_proto = "message Test { required bytes b = 1; }";
\r
407 var builder = ProtoBuf.loadProto(str_proto);
\r
408 var Test = builder.build("Test");
\r
409 var bb = new ByteBuffer(4).writeUint32(0x12345678).flip();
\r
410 var myTest = new Test(bb);
\r
411 test.strictEqual(myTest.b.array, bb.array);
\r
412 var bb2 = new ByteBuffer(6);
\r
413 var size = myTest.calculate();
\r
414 myTest.encode(bb2);
\r
415 test.strictEqual(bb2.offset, size);
\r
416 test.equal(bb2.flip().toString("debug"), "<0A 04 12 34 56 78>");
\r
417 myTest = Test.decode(bb2);
\r
418 test.equal(myTest.b.BE().readUint32(), 0x12345678);
\r
425 "bytesFromFile": function(test) {
\r
427 var builder = ProtoBuf.loadProto("message Image { required bytes data = 1; }"),
\r
428 Image = builder.build("Image"),
\r
429 data = fs.readFileSync(__dirname+"/../protobuf.png"),
\r
430 image = new Image({ data: data }),
\r
431 bb = image.encode(),
\r
432 imageDec = Image.decode(bb),
\r
433 dataDec = imageDec.data.toBuffer();
\r
434 test.strictEqual(data.length, dataDec.length);
\r
435 test.deepEqual(data, dataDec);
\r
442 "notEnoughBytes": function(test) {
\r
443 var builder = ProtoBuf.loadProto("message Test { required bytes b = 1; }");
\r
444 var Test = builder.build("Test");
\r
445 var bb = new ByteBuffer().writeUint32(0x12345678).flip();
\r
446 var encoded = new ByteBuffer(6);
\r
447 new Test(bb).encode(encoded);
\r
448 test.equal(encoded.flip().toString("debug"), "<0A 04 12 34 56 78>");
\r
449 encoded = encoded.slice(0, 5); // chop off the last byte
\r
452 Test.decode(encoded);
\r
456 test.ok(err && err.message && err.message.indexOf(": 4 required but got only 3") >= 0);
\r
460 "bool": function(test) {
\r
462 var builder = ProtoBuf.loadProto("message Test { optional bool ok = 1 [ default = false ]; }"),
\r
463 Test = builder.build("Test"),
\r
465 test.strictEqual(t.ok, null); // Not set as it is optional
\r
467 test.strictEqual(t.ok, true);
\r
468 test.strictEqual(Test.decode(t.encode()).ok, true);
\r
470 test.strictEqual(t.ok, false);
\r
471 t.setOk(null); // Not set
\r
472 test.strictEqual(Test.decode(t.encode()).ok, false); // = default when missing
\r
479 // As mentioned by Bill Katz
\r
480 "T139": function(test) {
\r
482 var builder = ProtoBuf.loadProtoFile(__dirname+"/T139.proto");
\r
483 var T139 = builder.build("T139");
\r
484 test.ok(typeof T139 == 'function');
\r
485 var inst = new T139(139,139);
\r
486 test.equal(inst.a, 139);
\r
487 test.equal(inst.b, 139);
\r
490 test.equal(inst.a, 139);
\r
491 test.equal(inst.b, 139);
\r
492 var bb = new ByteBuffer(3);
\r
494 test.equal(bb.flip().toString("debug"), "<08 8B 01 10 8B 01>");
\r
495 var instDec = T139.decode(bb);
\r
496 test.equal(instDec.a, 139);
\r
497 test.equal(instDec.b, 139);
\r
504 "emptyDefaultString": function(test) {
\r
506 var builder = ProtoBuf.loadProto("message Test1 { required string test = 1 [default = \"\"]; }");
\r
508 test.doesNotThrow(function() {
\r
509 Test1 = builder.build("Test1");
\r
511 var test1 = new Test1();
\r
512 test.strictEqual(test1.test, "");
\r
519 "trailingSemicolon": function(test) {
\r
521 var builder = ProtoBuf.loadProto("message Test1 { optional string test = 1; };");
\r
522 test.doesNotThrow(function() {
\r
523 var Test1 = builder.build("Test1");
\r
533 "longstr": function(test) {
\r
535 var builder = ProtoBuf.loadProto("message Test { required Inner a = 1; message Inner { required string b = 1; } }");
\r
536 var Test = builder.build("Test");
\r
537 var t = new Test();
\r
538 var data = "0123456789"; // 10: 20, 40, 80, 160, 320 bytes
\r
539 for (var i=0; i<5; i++) data += data;
\r
540 test.equal(data.length, 320);
\r
541 t.a = new Test.Inner(data);
\r
542 var bb = t.encode();
\r
543 var t2 = Test.decode(bb);
\r
544 test.equal(t2.a.b.length, 320);
\r
545 test.equal(data, t2.a.b);
\r
552 "multiple": function(test) {
\r
555 for (var i=0; i<200; i++) str += 'a';
\r
556 var builder = ProtoBuf.loadProtoFile(__dirname+"/inner.proto");
\r
557 var fooCls = builder.build("Foo");
\r
558 var barCls = builder.build("Bar");
\r
559 var bazCls = builder.build("Baz");
\r
560 var foo = new fooCls(new barCls(str), new bazCls(str));
\r
561 var fooEncoded = foo.encode();
\r
562 test.doesNotThrow(function() {
\r
563 fooCls.decode(fooEncoded);
\r
571 "float": function(test) {
\r
573 var builder = ProtoBuf.loadProto("message Foo { required Bar bar = 1; } message Bar { required float baz = 1; }");
\r
574 var root = builder.build();
\r
575 var foo = new root.Foo(new root.Bar(4));
\r
576 var bb = foo.encode();
\r
577 var foo2 = root.Foo.decode(bb);
\r
578 test.equal(foo.bar.baz, 4);
\r
579 test.equal(foo2.bar.baz, foo.bar.baz);
\r
588 "truncated": function(test) {
\r
590 var builder = ProtoBuf.loadProto("message Test { required int32 a = 1; required int32 b = 2; }");
\r
591 var Test = builder.build("Test");
\r
592 var t = new Test(), bb = new ByteBuffer(2);
\r
595 bb = t.encode(bb).flip();
\r
598 test.ok(e.encoded);
\r
599 bb = e.encoded.flip();
\r
600 test.equal(bb.toString("debug"), "<08 01>");
\r
603 try /* to decode truncated message */ {
\r
604 t2 = Test.decode(bb);
\r
605 test.ok(false); // ^ throws
\r
607 // But still be able to access the rest
\r
608 var t3 = e.decoded;
\r
609 test.strictEqual(t3.a, 1);
\r
610 test.strictEqual(t3.b, null);
\r
612 test.strictEqual(t2, undefined);
\r
619 // Options on all levels
\r
622 "parse": function(test) {
\r
624 var parser = new ProtoBuf.DotProto.Parser(ProtoBuf.Util.fetch(__dirname+"/options.proto"));
\r
625 var root = parser.parse();
\r
626 test.equal(root["package"], "My");
\r
627 test.strictEqual(root["options"]["(toplevel_1)"], 10);
\r
628 test.equal(root["options"]["(toplevel_2)"], "Hello world!");
\r
629 var opt = root["messages"][0]["fields"][0]["options"];
\r
630 test.equal(opt["default"], "Max");
\r
631 opt = root["messages"][0]["options"];
\r
632 test.strictEqual(opt["(inmessage)"], "My.Test");
\r
633 test.strictEqual(opt["(foo.my_option).bar"], false);
\r
634 opt = root["messages"][0]["fields"][1]["options"];
\r
635 test.strictEqual(opt["default"], "Shouldn't mix quotes");
\r
636 opt = root["messages"][0]["fields"][2]["options"];
\r
637 test.strictEqual(opt["default"], 'Shouldn"t mix quotes');
\r
638 opt = root["messages"][0]["fields"][3]["options"];
\r
639 test.strictEqual(opt["(foo_options).opt1"], 123);
\r
640 test.strictEqual(opt["(foo_options).opt2"], "baz");
\r
647 "export": function(test) {
\r
649 var builder = ProtoBuf.loadProtoFile(__dirname+"/options.proto");
\r
650 var My = builder.build("My");
\r
651 test.deepEqual(My.$options, {
\r
652 "(toplevel_1)": 10,
\r
653 "(toplevel_2)": "Hello world!"
\r
655 test.strictEqual(My.$options['(toplevel_1)'], 10);
\r
656 test.deepEqual(My.Test.$options, {
\r
657 "(inmessage)": "My.Test",
\r
658 "(foo.my_option).bar": false
\r
668 "comments": function(test) {
\r
670 var tn = new ProtoBuf.DotProto.Tokenizer(ProtoBuf.Util.fetch(__dirname+'/comments.proto'));
\r
671 var token, tokens = [];
\r
674 tokens.push(token);
\r
675 } while (token !== null);
\r
676 test.deepEqual(tokens, ['message', 'TestC', '{', 'required', 'int32', 'a', '=', '1', ';', '}', null]);
\r
683 // A more or less complex proto with type references
\r
684 "complexProto": function(test) {
\r
686 var builder = ProtoBuf.loadProtoFile(__dirname+"/complex.proto");
\r
687 validateComplex(test, builder.build("Game"));
\r
688 var TCars = builder.lookup("Game.Cars");
\r
689 test.strictEqual(TCars.fqn(), ".Game.Cars");
\r
696 // The same created without calling upon the parser to do so
\r
697 "complexJSON": function(test) {
\r
699 var builder = ProtoBuf.loadJsonFile(__dirname+"/complex.json");
\r
700 validateComplex(test, builder.build("Game"));
\r
707 // Test error messages
\r
708 "errorMessage": function(test) {
\r
709 test.throws(function() {
\r
710 var builder = ProtoBuf.loadJsonFile(__dirname+"/complex.json");
\r
711 var Game = builder.build("Game");
\r
712 var car = new Game.Cars.Car();
\r
713 car.speed = "hello";
\r
715 }, /Illegal value for speed/);
\r
719 // Builder reused to add definitions from multiple sources
\r
720 "multiBuilder": function(test) {
\r
722 var builder = ProtoBuf.loadProtoFile(__dirname+"/example1.proto");
\r
723 ProtoBuf.loadProtoFile(__dirname+"/example2.proto", builder);
\r
724 var ns = builder.build();
\r
725 test.ok(!!ns.Test1);
\r
726 test.ok(!!ns.Test2);
\r
733 // Inner messages test
\r
734 "inner": function(test) {
\r
736 var builder = ProtoBuf.loadProtoFile(__dirname+"/repeated.proto");
\r
737 var root = builder.build(),
\r
738 Outer = root.Outer,
\r
739 Inner = root.Inner;
\r
741 var outer = new Outer();
\r
742 var bb = new ByteBuffer(1).fill(0).flip();
\r
744 test.equal(bb.flip().toString("debug"), "|00");
\r
745 var douter = Outer.decode(bb);
\r
746 test.ok(douter.inner instanceof Array);
\r
747 test.equal(douter.inner.length, 0);
\r
749 outer = new Outer({ inner: [new Inner(1), new Inner(2)] });
\r
750 bb = new ByteBuffer(8);
\r
751 var size = outer.calculate();
\r
753 test.strictEqual(bb.offset, size);
\r
754 test.equal(bb.flip().toString("debug"), "<0A 02 08 01 0A 02 08 02>");
\r
755 douter = Outer.decode(bb);
\r
756 test.ok(douter.inner instanceof Array);
\r
757 test.equal(douter.inner.length, 2);
\r
758 test.equal(douter.inner[0].inner_value, 1);
\r
759 test.equal(douter.inner[1].inner_value, 2);
\r
766 // Packed vs. not packed repeated fields test
\r
767 "packed": function(test) {
\r
769 var builder = ProtoBuf.loadProtoFile(__dirname+"/packed.proto");
\r
770 var Message = builder.build("Message");
\r
772 var message = new Message();
\r
773 var bb = new ByteBuffer(1).fill(0).flip();
\r
774 var size = message.calculate();
\r
775 message.encode(bb);
\r
776 test.strictEqual(bb.offset, size);
\r
777 test.equal(bb.flip().toString("debug"), "|00");
\r
778 message = Message.decode(bb);
\r
779 test.ok(message.a instanceof Array);
\r
780 test.equal(message.a.length, 0);
\r
781 test.ok(message.b instanceof Array);
\r
782 test.equal(message.b.length, 0);
\r
784 message = new Message([1,2,3], [1,2,3]);
\r
785 size = message.calculate();
\r
786 message.encode(bb.resize(11));
\r
787 test.strictEqual(bb.offset, size);
\r
788 test.equal(bb.flip().toString("debug"), "<0A 03 01 02 03 10 01 10 02 10 03>");
\r
789 message = Message.decode(bb);
\r
790 test.ok(message.a instanceof Array);
\r
791 test.equal(message.a.length, 3);
\r
792 test.deepEqual(message.a, [1,2,3]);
\r
793 test.ok(message.b instanceof Array);
\r
794 test.equal(message.b.length, 3);
\r
795 test.deepEqual(message.b, [1,2,3]);
\r
802 // Legacy groups test
\r
803 "groups": function(test) {
\r
805 var builder = ProtoBuf.loadProtoFile(__dirname+"/groups.proto");
\r
806 var root = builder.build();
\r
807 var Outer = root.Outer;
\r
808 var TOuter = builder.ns.getChild("Outer");
\r
809 var TInner = TOuter.getChild("MyInner");
\r
810 test.ok(TInner instanceof ProtoBuf.Reflect.Message);
\r
811 test.strictEqual(TInner.isGroup, true);
\r
812 var Tinner = TOuter.getChild("myinner");
\r
813 test.ok(Tinner instanceof ProtoBuf.Reflect.Message.Field);
\r
814 test.strictEqual(Tinner.id, 2);
\r
815 test.deepEqual(Tinner.options, { "deprecated": true });
\r
816 var Inner = root.Outer.MyInner;
\r
817 var outer = new Outer("a", [new Inner("hello")], "b", new Inner("world"));
\r
818 var bb = new ByteBuffer();
\r
819 var size = outer.calculate();
\r
821 test.strictEqual(bb.offset, size);
\r
822 bb.flip().compact();
\r
824 "0A", // 1|010 = id 1, wire type 2 (ldelim)
\r
827 "13", // 10|011 = id 2, wire type 3 (start group)
\r
828 "1A", // 11|010 = id 3, wire type 2 (ldelim)
\r
830 "68 65 6C 6C 6F", // "hello"
\r
831 "14", // 10|100 = id 2, wire type 4 (end group)
\r
832 "22", // 100|010 = id 4, wire type 2 (ldelim)
\r
835 "2B", // 101|011 = id 5, wire type = 3 (start group)
\r
836 "1A", // 11|010 = id 3, wire type = 2 (ldelim)
\r
838 "77 6F 72 6C 64", // "world"
\r
839 "2C" // 101|100 = id 5, wire type = 4 (end group)
\r
841 test.equal(bb.toString("debug"), "<" +wiredMsg.join(" ") + ">");
\r
842 var douter = Outer.decode(bb);
\r
843 test.strictEqual(douter.before, "a");
\r
844 test.strictEqual(douter.myinner.length, 1);
\r
845 test.strictEqual(douter.myinner[0].a, "hello");
\r
846 test.strictEqual(douter.after, "b");
\r
848 douter = root.OuterSparse.decode(bb);
\r
849 test.strictEqual(bb.offset, bb.limit);
\r
850 test.strictEqual(douter.before, "a");
\r
851 test.strictEqual(douter.after, "b");
\r
858 "x64Fixed": function(test) {
\r
860 var builder = ProtoBuf.loadProtoFile(__dirname+"/x64.proto");
\r
861 var Test = builder.build("Test");
\r
862 var myTest = new Test();
\r
863 test.ok(myTest.val instanceof ByteBuffer.Long);
\r
864 test.equal(myTest.val.unsigned, false);
\r
865 test.equal(myTest.val.toNumber(), -1);
\r
866 test.ok(myTest.uval instanceof ByteBuffer.Long);
\r
867 test.equal(myTest.uval.unsigned, true);
\r
868 test.equal(myTest.uval.toNumber(), 1);
\r
871 var bb = new ByteBuffer(18); // 2x tag + 2x 64bit
\r
872 var size = myTest.calculate();
\r
874 test.strictEqual(bb.offset, size);
\r
875 test.equal(bb.flip().toString("debug"), "<09 FE FF FF FF FF FF FF FF 11 02 00 00 00 00 00 00 00>");
\r
876 // ^ wireType=1, id=1 ^ wireType=1, id=2
\r
877 myTest = Test.decode(bb);
\r
878 test.ok(myTest.val instanceof ByteBuffer.Long);
\r
879 test.equal(myTest.val.unsigned, false);
\r
880 test.equal(myTest.val.toNumber(), -2);
\r
881 test.ok(myTest.uval instanceof ByteBuffer.Long);
\r
882 test.equal(myTest.uval.unsigned, true);
\r
883 test.equal(myTest.uval.toNumber(), 2);
\r
890 "x64Varint": function(test) {
\r
892 var builder = ProtoBuf.loadProtoFile(__dirname+"/x64.proto");
\r
893 var Test = builder.build("Test2");
\r
894 var Test = builder.build("Test2");
\r
895 var myTest = new Test();
\r
896 test.ok(myTest.val instanceof ByteBuffer.Long);
\r
897 test.equal(myTest.val.unsigned, false);
\r
898 test.equal(myTest.val.toNumber(), -1);
\r
899 test.ok(myTest.uval instanceof ByteBuffer.Long);
\r
900 test.equal(myTest.uval.unsigned, true);
\r
901 test.equal(myTest.uval.toNumber(), 1);
\r
902 test.ok(myTest.sval instanceof ByteBuffer.Long);
\r
903 test.equal(myTest.sval.unsigned, false);
\r
904 test.equal(myTest.sval.toNumber(), -2);
\r
908 myTest.setSval(-3);
\r
909 var bb = new ByteBuffer(3+10+2); // 3x tag + 1x varint 10byte + 2x varint 1byte
\r
910 var size = myTest.calculate();
\r
912 test.strictEqual(bb.offset, size);
\r
913 test.equal(bb.flip().toString("debug"), "<08 FE FF FF FF FF FF FF FF FF 01 10 02 18 05>");
\r
914 // 08: wireType=0, id=1, 18: wireType=0, id=2, ?: wireType=0, id=3
\r
915 myTest = Test.decode(bb);
\r
916 test.ok(myTest.val instanceof ByteBuffer.Long);
\r
917 test.equal(myTest.val.unsigned, false);
\r
918 test.equal(myTest.val.toNumber(), -2);
\r
919 test.ok(myTest.uval instanceof ByteBuffer.Long);
\r
920 test.equal(myTest.uval.unsigned, true);
\r
921 test.equal(myTest.uval.toNumber(), 2);
\r
922 test.ok(myTest.sval instanceof ByteBuffer.Long);
\r
923 test.equal(myTest.sval.unsigned, false);
\r
924 test.equal(myTest.sval.toNumber(), -3);
\r
931 "keywords": function(test) {
\r
933 var builder = ProtoBuf.loadProto("message Reserved { optional string get = 1; }");
\r
934 var My = builder.build();
\r
935 var myTest = new My.Reserved("a");
\r
936 test.doesNotThrow(function() {
\r
945 "imports": function(test) {
\r
947 var builder = ProtoBuf.loadProtoFile(__dirname+"/imports.proto");
\r
948 var root = builder.build();
\r
949 test.ok(!!root.Test1);
\r
950 test.ok(!!root.Test2);
\r
951 test.ok(!!root.My.Test3);
\r
952 test.notEqual(root.Test2, root.My.Test2);
\r
959 "weakImports": function(test) {
\r
961 var builder = ProtoBuf.loadProtoFile(__dirname+"/imports-weak.proto");
\r
962 var root = builder.build();
\r
964 test.ok(e.message.indexOf("unresolvable type reference") >= 0);
\r
968 var e = new Error("Weak import was imported.");
\r
972 "importExtensions": function(test) {
\r
973 var x = "package x; \
\r
975 extensions 1 to 10; \
\r
978 optional int32 first_val = 1; \
\r
980 var y = "package y; \
\r
982 optional int32 second_val = 2; \
\r
984 var builder = ProtoBuf.newBuilder();
\r
985 ProtoBuf.loadProto(x, builder);
\r
986 ProtoBuf.loadProto(y, builder);
\r
987 var Test = builder.build('x.Test');
\r
988 var inst = new Test();
\r
989 test.strictEqual(inst[".x.first_val"], null);
\r
990 test.strictEqual(inst[".y.second_val"], null);
\r
994 "toplevel": function(test) {
\r
996 var builder = ProtoBuf.loadProtoFile(__dirname+"/toplevel.proto");
\r
997 var My = builder.build("My");
\r
998 test.ok(!!My.MyEnum);
\r
999 test.equal(My.MyEnum.ONE, 1);
\r
1000 test.equal(My.MyEnum.TWO, 2);
\r
1001 test.ok(!!My.Test);
\r
1002 var myTest = new My.Test();
\r
1003 test.equal(myTest.num, My.MyEnum.ONE);
\r
1010 "importsToplevel": function(test) {
\r
1012 var builder = ProtoBuf.loadProtoFile(__dirname+"/imports-toplevel.proto");
\r
1013 var My = builder.build("My");
\r
1014 test.ok(!!My.MyEnum);
\r
1015 test.equal(My.MyEnum1.ONE, 1);
\r
1016 test.equal(My.MyEnum1.TWO, 2);
\r
1017 test.ok(!!My.Test1);
\r
1018 var myTest = new My.Test1();
\r
1019 test.equal(myTest.num, My.MyEnum.ONE);
\r
1020 test.equal(myTest.num1, My.MyEnum1.ONE);
\r
1027 "importDuplicate": function(test) {
\r
1029 var builder = ProtoBuf.loadProtoFile(__dirname+"/import_a.proto");
\r
1030 test.doesNotThrow(function() {
\r
1031 ProtoBuf.loadProtoFile(__dirname+"/import_b.proto", builder);
\r
1033 var root = builder.build();
\r
1036 test.ok(root.Common);
\r
1043 "importDuplicateDifferentBuilder": function(test) {
\r
1045 var builderA = ProtoBuf.loadProtoFile(__dirname+"/import_a.proto");
\r
1047 test.doesNotThrow(function() {
\r
1048 builderB = ProtoBuf.loadProtoFile(__dirname+"/import_b.proto");
\r
1050 var rootA = builderA.build();
\r
1051 var rootB = builderB.build();
\r
1054 test.ok(rootA.Common);
\r
1055 test.ok(rootB.Common);
\r
1062 "dupimport": function(test) {
\r
1064 // Suppress logging result to stdout
\r
1065 fixture.capture(function() { return false;});
\r
1066 require(__dirname+"/../cli/pbjs.js").main(["node", "bin/pbjs", __dirname+"/dupimport/main.proto", "--quiet"]);
\r
1067 fixture.release();
\r
1069 fixture.release();
\r
1075 "field_name_same_as_package": function(test) {
\r
1077 fixture.capture(function() { return false;});
\r
1078 require(__dirname+"/../cli/pbjs.js").main(["node", "bin/pbjs", __dirname+"/field_name_same_as_package/main.proto", "--quiet"]);
\r
1079 fixture.release();
\r
1081 fixture.release();
\r
1087 "importRoot": function(test) {
\r
1089 var builder = ProtoBuf.loadProtoFile({
\r
1091 file: "importRoot/file1.proto"
\r
1093 var Test = builder.build("Test");
\r
1094 test.ok(new Test() instanceof ProtoBuf.Builder.Message);
\r
1101 "extend": function(test) {
\r
1103 var ast = new ProtoBuf.DotProto.Parser(fs.readFileSync(__dirname+"/extend.proto")).parse();
\r
1104 test.deepEqual(ast, { package: null,
\r
1106 [ { ref: 'google.protobuf.MessageOptions',
\r
1108 [ { rule: 'optional',
\r
1120 extensions: [ [ 2, 536870911 ] ] },
\r
1123 [ { rule: 'optional',
\r
1140 fields: [ { rule: 'optional', type: 'Foo', name: 'foo', options: {}, id: 3 } ] } ],
\r
1145 imports: [ 'google/protobuf/descriptor.proto' ],
\r
1150 var builder = ProtoBuf.loadProtoFile(__dirname+"/extend.proto");
\r
1151 var TFoo = builder.lookup(".Foo"),
\r
1152 TBar = builder.lookup(".Bar"),
\r
1153 TBarFoo = builder.lookup(".Bar.Foo"),
\r
1154 fields = TFoo.getChildren(ProtoBuf.Reflect.Message.Field);
\r
1155 test.strictEqual(fields.length, 2);
\r
1156 test.strictEqual(fields[0].name, ".bar");
\r
1157 test.strictEqual(fields[0].id, 2);
\r
1158 test.strictEqual(fields[1].name, ".Bar.foo");
\r
1159 test.strictEqual(fields[1].id, 3);
\r
1160 test.deepEqual(TFoo.extensions, [[2, ProtoBuf.ID_MAX]]); // explicitly defined
\r
1161 test.strictEqual(TBar.extensions, undefined); // none defined
\r
1162 test.deepEqual(TBar.getChild("foo"), { builder: builder, parent: TBar, name: "foo", field: TFoo.getChild('.Bar.foo') });
\r
1163 test.strictEqual(TBar.getChildren(ProtoBuf.Reflect.Message.Field).length, 0);
\r
1164 var root = builder.build();
\r
1165 test.strictEqual(TFoo.getChild(".Bar.foo").resolvedType, TBarFoo); // .Bar.Foo, not .Foo
\r
1166 var foo = new root.Foo(),
\r
1167 bar = new root.Bar();
\r
1168 foo['.bar'] = "123";
\r
1169 foo['.Bar.foo'] = bar;
\r
1170 test.equal(foo.encode().compact().toString("debug"), "<12 03 31 32 33 1A 00>");
\r
1177 // Custom options on all levels
\r
1178 // victorr (https://github.com/victorr)
\r
1179 "customOptions": function(test) {
\r
1181 var parser = new ProtoBuf.DotProto.Parser(ProtoBuf.Util.fetch(__dirname+"/custom-options.proto"));
\r
1182 var root = parser.parse();
\r
1183 test.equal(root["options"]["(my_file_option)"], "Hello world!");
\r
1184 test.equal(root["messages"][7]["options"]["(my_message_option)"], 1234);
\r
1185 test.equal(root["messages"][7]["fields"][0]["options"]["(my_field_option)"], 4.5);
\r
1186 // test.equal(root["services"]["MyService"]["options"]["my_service_option"], "FOO");
\r
1187 // TODO: add tests for my_enum_option, my_enum_value_option
\r
1194 "oneofs": function(test) {
\r
1196 var builder = ProtoBuf.loadProtoFile(__dirname+"/oneof.proto"),
\r
1197 MyOneOf = builder.build("MyOneOf"),
\r
1198 TOneOf = builder.lookup(".MyOneOf");
\r
1199 test.ok(TOneOf.getChild("my_oneof"));
\r
1200 var myOneOf = new MyOneOf();
\r
1201 test.strictEqual(myOneOf.my_oneof, null);
\r
1202 myOneOf.set("id", 1);
\r
1203 test.strictEqual(myOneOf.my_oneof, "id");
\r
1204 myOneOf.set("name", "me");
\r
1205 test.strictEqual(myOneOf.my_oneof, "name");
\r
1206 test.strictEqual(myOneOf.id, null);
\r
1207 var bb = myOneOf.encode().compact();
\r
1208 test.strictEqual(bb.toString("debug"), "<12 02 6D 65>"); // id 2, wt 2, len 2
\r
1209 myOneOf = MyOneOf.decode(bb);
\r
1210 test.strictEqual(myOneOf.my_oneof, "name");
\r
1211 test.strictEqual(myOneOf.name, "me");
\r
1212 test.strictEqual(myOneOf.id, null);
\r
1219 "services": function(test) {
\r
1221 var parser = new ProtoBuf.DotProto.Parser(ProtoBuf.Util.fetch(__dirname+"/custom-options.proto"));
\r
1222 var root = parser.parse();
\r
1223 test.deepEqual(root["services"], [{
\r
1224 "name": "MyService",
\r
1227 "request": "RequestType",
\r
1228 "response": "ResponseType",
\r
1229 "request_stream": false,
\r
1230 "response_stream": false,
\r
1232 "(my_method_option).foo": 567,
\r
1233 "(my_method_option).bar": "Some string"
\r
1238 "(my_service_option)": "FOO"
\r
1242 var builder = ProtoBuf.loadProtoFile(__dirname+"/custom-options.proto");
\r
1243 var root = builder.build(),
\r
1244 MyService = root.MyService,
\r
1245 RequestType = root.RequestType,
\r
1246 ResponseType = root.ResponseType,
\r
1249 test.deepEqual(MyService.$options, {
\r
1250 "(my_service_option)": "FOO"
\r
1252 test.deepEqual(MyService.MyMethod.$options, {
\r
1253 "(my_method_option).foo": 567,
\r
1254 "(my_method_option).bar": "Some string"
\r
1257 // Provide the service with your actual RPC implementation based on whatever framework you like most.
\r
1258 var myService = new MyService(function(method, req, callback) {
\r
1259 test.strictEqual(method, ".MyService.MyMethod");
\r
1260 test.ok(req instanceof RequestType);
\r
1263 // In this case we just return no error and our pre-built response. This must be properly async!
\r
1264 setTimeout(callback.bind(this, null, (new ResponseType()).encode() /* as raw bytes for debugging */ ));
\r
1267 test.deepEqual(myService.$options, MyService.$options);
\r
1268 test.deepEqual(myService.MyMethod.$options, MyService.MyMethod.$options);
\r
1270 // Call the service with your request message and provide a callback. This will call your actual service
\r
1271 // implementation to perform the request and gather a response before calling the callback. If the
\r
1272 // request or response type is invalid i.e. not an instance of RequestType or ResponseType, your
\r
1273 // implementation will not be called as ProtoBuf.js handles this case internally and directly hands the
\r
1274 // error to your callback below.
\r
1275 myService.MyMethod(new RequestType(), function(err, res) {
\r
1276 // We get: err = null, res = our prebuilt response. And that's it.
\r
1277 if (err !== null) {
\r
1280 test.strictEqual(called, true);
\r
1281 test.ok(res instanceof ResponseType);
\r
1284 myService.MyMethod(new RequestType().encode(), function(err, res) {
\r
1285 // We get: err = null, res = our prebuilt response. And that's it.
\r
1286 if (err !== null) {
\r
1289 test.strictEqual(called, true);
\r
1290 test.ok(res instanceof ResponseType);
\r
1298 // Properly ignore "syntax" and "extensions" keywords
\r
1299 // The corresponding .proto file has been removed upon request
\r
1300 /* "gtfs-realtime": function(test) {
\r
1302 test.doesNotThrow(function() {
\r
1303 ProtoBuf.loadProtoFile(__dirname+"/gtfs-realtime.proto");
\r
1311 "delimited": function(test) {
\r
1313 var builder = ProtoBuf.loadProto("message Position { required int32 x = 1; required int32 y = 2; }");
\r
1314 var Position = builder.build("Position");
\r
1315 var bb = new ByteBuffer();
\r
1316 for (var i=0; i<2; i++) {
\r
1317 var position = new Position(10,10);
\r
1318 position.encodeDelimited(bb);
\r
1321 for (i=0; i<2; i++) {
\r
1322 position = Position.decodeDelimited(bb);
\r
1323 test.strictEqual(position.x, 10);
\r
1324 test.strictEqual(position.y, 10);
\r
1332 "stringify": function(test) {
\r
1334 var builder = ProtoBuf.loadProto("message Position { required int32 x = 1; required int64 y = 2; }");
\r
1335 var Position = builder.build("Position");
\r
1336 var position = new Position(1, ProtoBuf.Long.fromNumber(2));
\r
1337 var json = JSON.stringify(position);
\r
1338 test.strictEqual(json, '{"x":1,"y":{"low":2,"high":0,"unsigned":false}}');
\r
1339 position = new Position(JSON.parse(json));
\r
1340 test.strictEqual(position.x, 1);
\r
1341 test.ok(position.y instanceof ProtoBuf.Long);
\r
1342 test.deepEqual(position.y, {"low":2,"high":0,"unsigned":false});
\r
1343 // Also test if this encodes and decodes properly
\r
1344 position = Position.decode(position.encode());
\r
1345 test.ok(position.y instanceof ProtoBuf.Long);
\r
1346 test.deepEqual(position.y, {"low": 2, "high": 0, "unsigned": false });
\r
1353 "fields": function(test) {
\r
1355 var builder = ProtoBuf.loadProtoFile(__dirname+"/optional.proto");
\r
1356 var Test1 = builder.build("Test1");
\r
1357 var test1 = new Test1();
\r
1358 test.strictEqual(test1.a, null);
\r
1359 test.deepEqual(Object.keys(test1), ['a','b']);
\r
1360 var bb = test1.encode();
\r
1361 test1 = Test1.decode(bb);
\r
1362 test.strictEqual(test1.a, null);
\r
1363 test.deepEqual(Object.keys(test1), ['a','b']);
\r
1370 "fieldsToCamelCase": function(test) {
\r
1372 ProtoBuf.convertFieldsToCamelCase = true;
\r
1373 var builder = ProtoBuf.loadProtoFile(__dirname+"/camelcase.proto");
\r
1374 var Test = builder.build("Test"),
\r
1375 TTest = builder.lookup("Test");
\r
1376 var msg = new Test();
\r
1378 // Reverted collision on 1st
\r
1379 test.strictEqual(msg.some_field, null);
\r
1380 test.strictEqual(msg.someField, null);
\r
1381 test.equal(TTest.getChild("some_field").id, 1);
\r
1382 test.equal(TTest.getChild("someField").id, 2);
\r
1385 // Reverted collision on 2nd
\r
1386 test.strictEqual(msg.aField, null);
\r
1387 test.strictEqual(msg.a_field, null);
\r
1388 test.equal(TTest.getChild("aField").id, 3);
\r
1389 test.equal(TTest.getChild("a_field").id, 4);
\r
1392 test.strictEqual(msg.itsAField, null);
\r
1393 test.equal(TTest.getChild("itsAField").id, 5);
\r
1395 test.ok(typeof msg.set_its_a_field === "function");
\r
1396 test.ok(typeof msg.setItsAField === "function");
\r
1398 ProtoBuf.convertFieldsToCamelCase = false;
\r
1400 ProtoBuf.convertFieldsToCamelCase = false;
\r
1406 "setarray": function(test) {
\r
1408 var builder = ProtoBuf.loadProtoFile(__dirname+"/setarray.proto");
\r
1409 var root = builder.build(),
\r
1410 Outer = root.Outer,
\r
1411 Inner = root.Inner,
\r
1414 // Array of repeated messages
\r
1415 inners.push(new Inner("a"), new Inner("b"), new Inner("c"));
\r
1416 var outer = new Outer();
\r
1417 outer.setInners(inners);
\r
1418 test.deepEqual(outer.inners, inners);
\r
1420 // Array of repeated message objects
\r
1422 inners.push({ str: 'a' }, { str: 'b' }, { str: 'c' });
\r
1423 outer.setInners(inners); // Converts
\r
1424 test.ok(outer.inners[0] instanceof Inner);
\r
1425 test.deepEqual(outer.inners, inners);
\r
1433 // Make sure that our example at https://github.com/dcodeIO/ProtoBuf.js/wiki is not nonsense
\r
1434 "pingexample": function(test) {
\r
1436 var builder = ProtoBuf.loadProtoFile(__dirname+"/PingExample.proto");
\r
1437 var Message = builder.build("Message");
\r
1438 var msg = new Message();
\r
1439 msg.ping = new Message.Ping(123456789);
\r
1440 var bb = msg.encode();
\r
1441 test.strictEqual(bb.limit, 7);
\r
1442 msg = Message.decode(bb);
\r
1443 test.ok(msg.ping);
\r
1444 test.notOk(msg.pong);
\r
1445 test.strictEqual(msg.ping.time, 123456789);
\r
1452 "negInt32": function(test) {
\r
1454 var builder = ProtoBuf.loadProto("message Test { required int32 value = 2; }");
\r
1455 var Test = builder.build("Test");
\r
1456 var t = new Test(-1);
\r
1457 var size = t.calculate();
\r
1458 var bb = t.encode(); // flips
\r
1459 test.strictEqual(bb.remaining(), size);
\r
1460 test.strictEqual(bb.toBase64(), "EP///////////wE=");
\r
1461 t = Test.decode(bb);
\r
1462 test.strictEqual(t.value, -1);
\r
1469 "negEnumId": function(test) {
\r
1471 test.doesNotThrow(function() {
\r
1472 var builder = ProtoBuf.loadProtoFile(__dirname+"/negid.proto");
\r
1473 var Test = builder.build("Test");
\r
1474 test.strictEqual(Test.LobbyType.INVALID, -1);
\r
1475 var t = new Test(Test.LobbyType.INVALID);
\r
1476 test.strictEqual(t.type, -1);
\r
1477 var size = t.calculate();
\r
1478 var bb = t.encode(); // flips
\r
1479 test.strictEqual(bb.remaining(), size);
\r
1480 t = Test.decode(bb);
\r
1481 test.strictEqual(t.type, -1);
\r
1489 "base64": function(test) {
\r
1491 var Message = ProtoBuf.loadProto("message Message { required string s = 1; }").build("Message");
\r
1492 var msg = new Message("ProtoBuf.js");
\r
1493 var b64 = msg.toBase64();
\r
1494 test.strictEqual(b64, "CgtQcm90b0J1Zi5qcw==");
\r
1495 var msg2 = Message.decode64(b64);
\r
1496 test.deepEqual(msg, msg2);
\r
1497 msg2 = Message.decode(b64, "base64");
\r
1498 test.deepEqual(msg, msg2);
\r
1505 "hex": function(test) {
\r
1507 var Message = ProtoBuf.loadProto("message Message { required string s = 1; }").build("Message");
\r
1508 var msg = new Message("ProtoBuf.js");
\r
1509 var hex = msg.toHex();
\r
1510 test.strictEqual(hex, "0a0b50726f746f4275662e6a73");
\r
1511 var msg2 = Message.decodeHex(hex);
\r
1512 test.deepEqual(msg, msg2);
\r
1513 msg2 = Message.decode(hex, "hex");
\r
1514 test.deepEqual(msg, msg2);
\r
1521 "forwardComp": function(test) {
\r
1523 var Message = ProtoBuf.loadProto("message Message { required int32 a = 1; required string b = 2; required float c = 3; }").build("Message");
\r
1524 var msg = new Message(123, "abc", 0.123);
\r
1525 var bb = msg.encode();
\r
1526 Message = ProtoBuf.loadProto("message Message {}").build("Message");
\r
1527 test.doesNotThrow(function() {
\r
1528 Message.decode(bb);
\r
1530 test.strictEqual(bb.offset, bb.limit);
\r
1537 "tokenizerLine": function(test) {
\r
1539 var parser = new ProtoBuf.DotProto.Parser("package test;\n\nmessage Message {\n\trequired string invalid = 1;}ERROR\n"),
\r
1540 ast = null, err = null;
\r
1542 ast = parser.parse();
\r
1543 } catch (caught) {
\r
1548 test.ok(err.message.indexOf("line 4:") >= 0);
\r
1555 "excludeFields": function(test) {
\r
1557 var builder = ProtoBuf.loadProto("message A { required int32 i = 1; } message B { required A A = 1; }");
\r
1565 "proto2jsExtend": function(test) {
\r
1567 var builder = ProtoBuf.loadJsonFile(__dirname+"/proto2js/Bar.json");
\r
1575 "emptyMessage": function(test) {
\r
1577 var builder = ProtoBuf.loadProto("message EmptyMessage {}"),
\r
1578 EmptyMessage = builder.build("EmptyMessage");
\r
1580 var msg = new EmptyMessage(),
\r
1581 ab = msg.toArrayBuffer();
\r
1582 test.strictEqual(ab.byteLength, 0);
\r
1589 "toRaw": function(test) {
\r
1591 var builder = ProtoBuf.loadProto("message MyMessage { required int32 a = 1; required int32 b = 2; required bytes c = 3; }"),
\r
1592 MyMessage = builder.build("MyMessage");
\r
1593 var raw = { a: 1, b: 2, c: "YWJj" },
\r
1594 myMessage = new MyMessage(raw);
\r
1595 test.deepEqual(myMessage.c.toBase64(), raw.c);
\r
1596 test.deepEqual(myMessage.toRaw(true), raw);
\r
1603 "singleQuotedString": function(test) {
\r
1605 var builder = ProtoBuf.loadProtoFile(__dirname+"/string_single_quote.proto");
\r
1606 var TestSingleQuoteString = builder.build("TestSingleQuoteString");
\r
1607 test.ok(typeof TestSingleQuoteString == 'function');
\r
1614 "importDuplicateSingleQuote": function(test) {
\r
1616 var builder = ProtoBuf.loadProtoFile(__dirname+"/import_a_single_quote.proto");
\r
1617 test.doesNotThrow(function() {
\r
1618 ProtoBuf.loadProtoFile(__dirname+"/import_b.proto", builder);
\r
1620 var root = builder.build();
\r
1623 test.ok(root.Common);
\r
1630 "importStringSuccessively": function(test) {
\r
1632 var proto1 = "message A { required string a = 1; };";
\r
1633 var proto2 = "import \"proto1.proto\"; message B { required A a = 1; };";
\r
1634 var builder = ProtoBuf.loadProto(proto1, "proto1.proto");
\r
1635 ProtoBuf.loadProto(proto2, builder, "proto2.proto");
\r
1636 var root = builder.build();
\r
1645 "multilineString": function(test) {
\r
1647 var proto = "message TestMessage { required string test = 1 [default = \"1\" \"2\"\n\"3\"];}";
\r
1648 var builder = ProtoBuf.loadProto(proto, "multilineString.proto");
\r
1649 var TestMessage = builder.build("TestMessage"),
\r
1650 testMessage = new TestMessage();
\r
1651 test.strictEqual(testMessage.test, "123");
\r
1659 "packable": function(test) {
\r
1661 var proto = 'message Inner { required int32 id=2; }\nmessage Outer { repeated Inner inner = 1 [packed=true]; }';
\r
1662 var builder = ProtoBuf.loadProto(proto);
\r
1663 var root = builder.build();
\r
1664 var inner = new root.Inner(1),
\r
1665 outer = new root.Outer(inner);
\r
1666 var bb = outer.encode().compact();
\r
1667 test.strictEqual(bb.toDebug(), "<0A 02 10 01>");
\r
1672 var outer2 = root.Outer.decode(bb);
\r
1673 test.strictEqual(outer2.inner.id, 1);
\r
1680 "$type": function(test) {
\r
1681 var builder = ProtoBuf.loadProto("message Test {}");
\r
1682 var Test = builder.build("Test"),
\r
1683 TTest = builder.lookup("Test");
\r
1684 test.strictEqual(new Test().$type, TTest);
\r
1688 "descriptor": function(test) {
\r
1690 var proto = 'import "./google/protobuf/descriptor.proto";';
\r
1691 var builder = ProtoBuf.loadProto(proto, "tests/proto.proto");
\r
1692 var root = builder.build("google.protobuf");
\r
1693 test.ok(root.FileDescriptorSet);
\r
1700 "mismatchedNesting": function(test) {
\r
1702 var proto = "message Child { optional uint32 foo = 1; } message FakeChild { optional uint32 foo = 1; } message Parent { optional Child child = 1; }";
\r
1703 var builder = ProtoBuf.loadProto(proto, "tests/mismatchedNesting.proto");
\r
1704 var root = builder.build();
\r
1705 var foo = new root.Parent({ child: new root.FakeChild({ foo: 1 })});
\r
1712 /* "mismatchedType": function(test) {
\r
1714 var proto = "message Test1 { optional string foo = 1; }";
\r
1715 proto += "message Test2 { optional int32 foo = 1; }";
\r
1716 var builder = ProtoBuf.loadProto(proto, "tests/mistmatchedType.proto");
\r
1717 var root = builder.build();
\r
1718 var test1 = new root.Test1({ foo: 'bar' });
\r
1719 var test2 = root.Test2.decode(test1.encode());
\r
1726 "builderOptions": function(test) {
\r
1728 var proto = "message Foo { optional uint32 foo_bar = 1; }";
\r
1729 var builder = ProtoBuf.newBuilder({
\r
1730 convertFieldsToCamelCase: true
\r
1732 ProtoBuf.loadProto(proto, builder, "tests/builderOptions.proto");
\r
1733 var Foo = builder.build("Foo");
\r
1734 test.strictEqual(ProtoBuf.convertFieldsToCamelCase, false);
\r
1735 test.strictEqual(builder.options.convertFieldsToCamelCase, true);
\r
1736 var foo = new Foo();
\r
1737 test.ok(typeof foo.fooBar !== 'undefined');
\r
1738 test.ok(typeof foo.foo_bar === 'undefined');
\r
1746 "proto3": function(test) {
\r
1748 var builder = ProtoBuf.loadProtoFile(__dirname+"/proto3.proto");
\r
1749 test.doesNotThrow(function() {
\r
1750 ProtoBuf.loadProtoFile(__dirname+"/proto3.proto", builder);
\r
1752 var root = builder.build();
\r
1753 test.ok(root.test.Foo.$type.syntax === 'proto3');
\r
1760 // FIXME: This test relied on some bloated builder functionality that has been removed.
\r
1761 // Is it even mandatory to strictly disallow proto2/3 mixing, even if that would be illegal in the official
\r
1762 // implementation?
\r
1763 /* "proto3DisallowedFeatures": function(test) {
\r
1766 var proto = "syntax = \"proto3\"; message Foo { required int32 field = 1; }";
\r
1767 var builder = ProtoBuf.newBuilder();
\r
1768 ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
\r
1769 test.ok(false); // ^ should throw
\r
1771 test.ok(/^Not a valid definition/.test(e.message));
\r
1775 // Field with default value
\r
1776 var proto = "syntax = \"proto3\"; message Foo { int32 field = 1 [default=42]; }";
\r
1777 var builder = ProtoBuf.newBuilder();
\r
1778 ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
\r
1779 test.ok(false); // ^ should throw
\r
1781 test.ok(/^Not a valid definition/.test(e.message));
\r
1785 // Message with extension range
\r
1786 var proto = "syntax = \"proto3\"; message Foo { extensions 100 to max; } ";
\r
1787 var builder = ProtoBuf.newBuilder();
\r
1788 ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
\r
1789 test.ok(false); // ^ should throw
\r
1791 test.ok(/^Not a valid definition/.test(e.message));
\r
1795 // Message with extension
\r
1796 var proto = "syntax = \"proto3\"; message Foo { extensions 100 to max; } " +
\r
1797 "message Bar { extend Foo { optional Bar bar = 100; } }";
\r
1798 var builder = ProtoBuf.newBuilder();
\r
1799 ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
\r
1800 test.ok(false); // ^ should throw
\r
1802 test.ok(/^Not a valid definition/.test(e.message));
\r
1806 // Enum with non-zero first entry.
\r
1807 var proto = "syntax = \"proto3\"; enum E { A = 1; B = 2; }";
\r
1808 var builder = ProtoBuf.newBuilder();
\r
1809 ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
\r
1810 test.ok(false); // ^ should throw
\r
1812 test.ok(/^Not a valid definition/.test(e.message));
\r
1816 // Proto3 message referring to proto2 enum.
\r
1817 var proto2 = "syntax = \"proto2\"; enum E { A = 1; B = 2; }";
\r
1818 var proto3 = "syntax = \"proto3\"; message Test { E enum_field = 1; }";
\r
1819 var builder = ProtoBuf.newBuilder();
\r
1820 ProtoBuf.loadProto(proto2, builder, "tests/proto3DisallowedFeatures1.proto");
\r
1821 ProtoBuf.loadProto(proto3, builder, "tests/proto3DisallowedFeatures3.proto");
\r
1822 test.ok(false); // ^ should throw
\r
1824 test.ok(/^Proto3 message refers to proto2 enum/.test(e.message));
\r
1830 "proto3FieldPresence": function(test) {
\r
1832 "syntax = \"proto3\";\n" +
\r
1833 "message Test {\n" +
\r
1834 " int32 field_int32 = 1;\n" +
\r
1835 " int64 field_int64 = 2;\n" +
\r
1836 " string field_str = 3;\n" +
\r
1837 " bytes field_bytes = 4;\n" +
\r
1838 " Test field_msg = 5;\n" +
\r
1839 " Enum field_enum = 6;\n" +
\r
1840 " repeated int32 rpt_int32 = 11;\n" +
\r
1841 " repeated int64 rpt_int64 = 12;\n" +
\r
1842 " repeated string rpt_str = 13;\n" +
\r
1843 " repeated bytes rpt_bytes = 14;\n" +
\r
1844 " repeated Test rpt_msg = 15;\n" +
\r
1845 " repeated Enum rpt_enum = 16;\n" +
\r
1846 " oneof oneof_type { bool oneof_bool = 17; };\n" +
\r
1848 "enum Enum { Default = 0; A = 1; B = 2; }\n";
\r
1849 var builder = ProtoBuf.newBuilder();
\r
1850 ProtoBuf.loadProto(proto, builder, "test/proto3FieldPresence.proto");
\r
1851 var Test = builder.build('Test'),
\r
1852 Enum = builder.build('Enum');
\r
1854 var testMsg = new Test();
\r
1855 test.strictEqual(testMsg.field_int32, 0);
\r
1856 test.strictEqual(testMsg.field_int64.low, 0);
\r
1857 test.strictEqual(testMsg.field_int64.high, 0);
\r
1858 test.strictEqual(testMsg.field_str, "");
\r
1859 test.strictEqual(testMsg.field_msg, null);
\r
1860 test.ok(testMsg.field_bytes instanceof ByteBuffer);
\r
1861 test.strictEqual(testMsg.field_bytes.remaining(), 0);
\r
1862 test.strictEqual(testMsg.rpt_int32.length, 0);
\r
1863 test.strictEqual(testMsg.oneof_type, null);
\r
1864 test.strictEqual(testMsg.oneof_bool, false);
\r
1866 // No fields should go on the wire, even though they're set
\r
1867 var encoded = testMsg.encode();
\r
1868 test.strictEqual(encoded.remaining(), 0);
\r
1869 testMsg.field_int32 = 42;
\r
1870 encoded = testMsg.encode();
\r
1871 test.strictEqual(encoded.remaining(), 2);
\r
1872 testMsg.field_int32 = 0;
\r
1873 encoded = testMsg.encode();
\r
1874 test.strictEqual(encoded.remaining(), 0);
\r
1876 // Enum fields should be able to carry arbitrary values.
\r
1877 testMsg.field_enum = 42;
\r
1878 test.strictEqual(testMsg.field_enum, 42);
\r
1879 encoded = testMsg.encode();
\r
1880 testMsg = Test.decode(encoded);
\r
1881 test.strictEqual(testMsg.field_enum, 42);
\r
1883 // Explicitly set fields that are part of an oneof should
\r
1884 // be encoded even if set to their default value
\r
1885 testMsg = new Test();
\r
1886 testMsg.set("oneof_bool", false);
\r
1887 test.strictEqual(testMsg.oneof_type, "oneof_bool");
\r
1888 encoded = testMsg.encode().compact();
\r
1889 test.strictEqual(encoded.toString("debug"), "<88 01 00>"); // 17|varint (0term) + varint 0
\r
1890 var decoded = Test.decode(encoded);
\r
1891 test.strictEqual(decoded.oneof_type, "oneof_bool");
\r
1892 test.strictEqual(decoded.oneof_bool, false);
\r
1897 "mapContainer": function(test) {
\r
1899 "message Test {\n" +
\r
1900 " map<string, int32> map_string_int32 = 1;\n" +
\r
1901 " map<string, int64> map_string_int64 = 2;\n" +
\r
1902 " map<string, string> map_string_string = 3;\n" +
\r
1903 " map<string, Test> map_string_msg = 4;\n" +
\r
1904 " map<string, Enum> map_string_enum = 5;\n" +
\r
1905 " map<int32, string> map_int32_string = 6;\n" +
\r
1906 " map<int64, string> map_int64_string = 7;\n" +
\r
1907 " map<bool, string> map_bool_string = 9;\n" +
\r
1909 "enum Enum { Default = 0; A = 1; B = 2; }\n";
\r
1910 var builder = ProtoBuf.newBuilder();
\r
1911 ProtoBuf.loadProto(proto, builder, "test/mapContainer.proto");
\r
1913 var map_string_int32 =
\r
1914 new ProtoBuf.Map(builder.lookup("Test.map_string_int32"));
\r
1915 test.strictEqual(map_string_int32.size, 0);
\r
1916 test.strictEqual(map_string_int32.has("asdf"), false);
\r
1917 test.strictEqual(map_string_int32.get("asdf"), undefined);
\r
1918 map_string_int32.set("asdf", 42);
\r
1919 test.strictEqual(map_string_int32.has("asdf"), true);
\r
1920 test.strictEqual(map_string_int32.get("asdf"), 42);
\r
1922 var it = map_string_int32.keys();
\r
1923 var itVal = it.next();
\r
1924 test.strictEqual(itVal.done, false);
\r
1925 test.strictEqual(itVal.value, "asdf");
\r
1926 itVal = it.next();
\r
1927 test.strictEqual(itVal.done, true);
\r
1929 it = map_string_int32.values();
\r
1930 itVal = it.next();
\r
1931 test.strictEqual(itVal.done, false);
\r
1932 test.strictEqual(itVal.value, 42);
\r
1933 itVal = it.next();
\r
1934 test.strictEqual(itVal.done, true);
\r
1936 it = map_string_int32.entries();
\r
1937 itVal = it.next();
\r
1938 test.strictEqual(itVal.done, false);
\r
1939 test.deepEqual(itVal.value, ["asdf", 42]);
\r
1940 itVal = it.next();
\r
1941 test.strictEqual(itVal.done, true);
\r
1943 map_string_int32.set("jkl;", 84);
\r
1944 test.strictEqual(map_string_int32.has("jkl;"), true);
\r
1945 test.strictEqual(map_string_int32.has("asdf"), true);
\r
1946 test.strictEqual(map_string_int32.size, 2);
\r
1947 map_string_int32.delete("jkl;");
\r
1948 test.strictEqual(map_string_int32.has("jkl;"), false);
\r
1949 test.strictEqual(map_string_int32.get("jkl;"), undefined);
\r
1950 test.strictEqual(map_string_int32.size, 1);
\r
1952 map_string_int32.clear();
\r
1953 test.strictEqual(map_string_int32.size, 0);
\r
1956 map_string_int32.set("asdf", 42.1);
\r
1957 test.ok(false); // ^ should throw
\r
1959 test.ok(e.message.match(/not an integer/));
\r
1963 map_string_int32.set(42, 42);
\r
1964 test.ok(false); // ^ should throw
\r
1966 test.ok(e.message.match(/not a string/));
\r
1969 // Test various key types to ensure that value->string->value
\r
1970 // conversion works.
\r
1971 var map_int32_string =
\r
1972 new ProtoBuf.Map(builder.lookup("Test.map_int32_string"));
\r
1973 test.strictEqual(map_int32_string.size, 0);
\r
1974 map_int32_string.set(12345678, "asdf");
\r
1975 test.strictEqual(map_int32_string.size, 1);
\r
1976 test.strictEqual(map_int32_string.has(12345678), true);
\r
1977 test.strictEqual(map_int32_string.get(12345678), "asdf");
\r
1979 var map_int64_string =
\r
1980 new ProtoBuf.Map(builder.lookup("Test.map_int64_string"));
\r
1981 test.strictEqual(map_int64_string.size, 0);
\r
1982 map_int64_string.set("9223372036854775807", "asdf");
\r
1983 test.strictEqual(map_int64_string.size, 1);
\r
1984 test.strictEqual(map_int64_string.has("9223372036854775807"), true);
\r
1985 test.strictEqual(map_int64_string.get("9223372036854775807"), "asdf");
\r
1987 // Ensure that initialization from a raw object works.
\r
1988 var map_int32_string =
\r
1989 new ProtoBuf.Map(builder.lookup("Test.map_int32_string"),
\r
1991 test.strictEqual(map_int32_string.size, 1);
\r
1992 test.strictEqual(map_int32_string.keys().next().value, 42);
\r
1994 var map_int64_string =
\r
1995 new ProtoBuf.Map(builder.lookup("Test.map_int64_string"),
\r
1996 { "9223372036854775807": "asdf" });
\r
1997 test.strictEqual(map_int64_string.size, 1);
\r
1998 var i64 = map_int64_string.keys().next().value;
\r
1999 test.ok(i64 instanceof ProtoBuf.Long);
\r
2000 test.strictEqual(i64.toString(), "9223372036854775807");
\r
2005 "mapField": function(test) {
\r
2007 "message Test {\n" +
\r
2008 " map<string, int32> map_string_int32 = 1;\n" +
\r
2009 " map<string, int64> map_string_int64 = 2;\n" +
\r
2010 " map<string, string> map_string_string = 3;\n" +
\r
2011 " map<string, Test> map_string_msg = 4;\n" +
\r
2012 " map<string, Enum> map_string_enum = 5;\n" +
\r
2013 " map<int32, string> map_int32_string = 6;\n" +
\r
2014 " map<int64, string> map_int64_string = 7;\n" +
\r
2015 " map<bool, string> map_bool_string = 9;\n" +
\r
2017 "enum Enum { Default = 0; A = 1; B = 2; }\n";
\r
2018 var builder = ProtoBuf.newBuilder();
\r
2019 ProtoBuf.loadProto(proto, builder, "test/mapField.proto");
\r
2020 var Test = builder.build('Test'),
\r
2021 Enum = builder.build('Enum');
\r
2023 var testMsg = new Test();
\r
2024 test.strictEqual(testMsg.map_string_int32.size, 0);
\r
2025 test.strictEqual(testMsg.map_string_int64.size, 0);
\r
2026 test.strictEqual(testMsg.map_string_string.size, 0);
\r
2027 test.strictEqual(testMsg.map_string_msg.size, 0);
\r
2028 test.strictEqual(testMsg.map_string_enum.size, 0);
\r
2029 test.strictEqual(testMsg.map_int32_string.size, 0);
\r
2030 test.strictEqual(testMsg.map_int64_string.size, 0);
\r
2031 test.strictEqual(testMsg.map_bool_string.size, 0);
\r
2033 testMsg.$set('map_string_int32', { 'asdf': 42 });
\r
2036 testMsg.$set('map_string_int32', { 'asdf': 42.1 });
\r
2037 test.ok(false); // ^ should throw
\r
2039 test.ok(e.message.match(/Illegal/));
\r
2045 "mapEncodeDecode": function(test) {
\r
2047 "message Test {\n" +
\r
2048 " map<string, int32> map_string_int32 = 1;\n" +
\r
2049 " map<string, int64> map_string_int64 = 2;\n" +
\r
2050 " map<string, string> map_string_string = 3;\n" +
\r
2051 " map<string, Test> map_string_msg = 4;\n" +
\r
2052 " map<string, Enum> map_string_enum = 5;\n" +
\r
2053 " map<int32, string> map_int32_string = 6;\n" +
\r
2054 " map<int64, string> map_int64_string = 7;\n" +
\r
2055 " map<bool, string> map_bool_string = 9;\n" +
\r
2057 "enum Enum { Default = 0; A = 1; B = 2; }\n";
\r
2058 var builder = ProtoBuf.newBuilder();
\r
2059 ProtoBuf.loadProto(proto, builder, "test/mapField.proto");
\r
2060 var Test = builder.build('Test'),
\r
2061 Enum = builder.build('Enum');
\r
2063 var testMsg = new Test();
\r
2064 testMsg.map_string_int32.set("a", 1);
\r
2065 testMsg.map_string_int32.set("b", 2);
\r
2066 testMsg.map_string_int64.set("c", "12345678901234");
\r
2067 testMsg.map_string_int64.set("d", "98765432109876");
\r
2068 testMsg.map_string_string.set("e", "asdf");
\r
2069 testMsg.map_string_string.set("f", "jkl;");
\r
2070 testMsg.map_string_enum.set("g", Enum.A);
\r
2071 testMsg.map_string_enum.set("h", Enum.B);
\r
2072 testMsg.map_int32_string.set(9, "a");
\r
2073 testMsg.map_int32_string.set(10, "b");
\r
2074 testMsg.map_int64_string.set("12345678901234", "a");
\r
2075 testMsg.map_int64_string.set("98765432109876", "b");
\r
2076 testMsg.map_bool_string.set(false, "a");
\r
2077 testMsg.map_bool_string.set(true, "b");
\r
2079 var encoded = testMsg.encode();
\r
2080 testMsg = Test.decode(encoded);
\r
2082 test.strictEqual(testMsg.map_string_int32.get("a"), 1);
\r
2083 test.strictEqual(testMsg.map_string_int32.get("b"), 2);
\r
2084 test.strictEqual(testMsg.map_string_int64.get("c").toString(), "12345678901234");
\r
2085 test.strictEqual(testMsg.map_string_int64.get("d").toString(), "98765432109876");
\r
2086 test.strictEqual(testMsg.map_string_string.get("e"), "asdf");
\r
2087 test.strictEqual(testMsg.map_string_string.get("f"), "jkl;");
\r
2088 test.strictEqual(testMsg.map_string_enum.get("g"), Enum.A);
\r
2089 test.strictEqual(testMsg.map_string_enum.get("h"), Enum.B);
\r
2090 test.strictEqual(testMsg.map_int32_string.get(9), "a");
\r
2091 test.strictEqual(testMsg.map_int32_string.get(10), "b");
\r
2092 test.strictEqual(testMsg.map_int64_string.get("12345678901234"), "a");
\r
2093 test.strictEqual(testMsg.map_int64_string.get("98765432109876"), "b");
\r
2094 test.strictEqual(testMsg.map_bool_string.get(false), "a");
\r
2095 test.strictEqual(testMsg.map_bool_string.get(true), "b");
\r
2100 "proto3Json": function(test) {
\r
2102 "syntax = \"proto3\";\n" +
\r
2103 "message Test {\n" +
\r
2104 " int32 optional_int32 = 1;\n" +
\r
2105 " int64 optional_int64 = 2;\n" +
\r
2106 " string optional_string = 3;\n" +
\r
2107 " bytes optional_bytes = 4;\n" +
\r
2108 " bool optional_bool = 5;\n" +
\r
2109 " Enum optional_enum = 6;\n" +
\r
2110 " repeated int32 repeated_int32 = 11;\n" +
\r
2111 " repeated int64 repeated_int64 = 12;\n" +
\r
2112 " repeated string repeated_string = 13;\n" +
\r
2113 " repeated bytes repeated_bytes = 14;\n" +
\r
2114 " repeated bool repeated_bool = 15;\n" +
\r
2115 " repeated Enum repeated_enum = 16;\n" +
\r
2116 " map<string, int32> map_string_int32 = 20;\n" +
\r
2117 " map<string, int64> map_string_int64 = 21;\n" +
\r
2118 " map<string, string> map_string_string = 22;\n" +
\r
2119 " map<string, Enum> map_string_enum = 24;\n" +
\r
2120 " map<int32, string> map_int32_string = 25;\n" +
\r
2121 " map<int64, string> map_int64_string = 26;\n" +
\r
2122 " map<bool, string> map_bool_string = 27;\n" +
\r
2124 "enum Enum { Default = 0; A = 1; B = 2; }\n";
\r
2125 var builder = ProtoBuf.newBuilder();
\r
2126 ProtoBuf.loadProto(proto, builder, "test/mapField.proto");
\r
2127 var Test = builder.build('Test'),
\r
2128 Enum = builder.build('Enum');
\r
2130 var testMsg = new Test();
\r
2131 testMsg.optional_int32 = 1;
\r
2132 testMsg.optional_int64 = "12345678901234";
\r
2133 testMsg.optional_string = "hello";
\r
2134 testMsg.optional_bytes = ProtoBuf.ByteBuffer.fromBinary("\x00\xFF\x80");
\r
2135 testMsg.optional_bool = true;
\r
2136 testMsg.optional_enum = Enum.A;
\r
2137 testMsg.repeated_int32.push(1);
\r
2138 testMsg.repeated_int64.push("12345678901234");
\r
2139 testMsg.repeated_string.push("hello");
\r
2140 testMsg.repeated_bytes.push(ProtoBuf.ByteBuffer.fromBinary("\x00\xFF\x80"));
\r
2141 testMsg.repeated_bool.push(true);
\r
2142 testMsg.repeated_enum.push(Enum.A);
\r
2143 testMsg.map_string_int32.set("a", 1);
\r
2144 testMsg.map_string_int32.set("b", 2);
\r
2145 testMsg.map_string_int64.set("c", "12345678901234");
\r
2146 testMsg.map_string_int64.set("d", "98765432109876");
\r
2147 testMsg.map_string_string.set("e", "asdf");
\r
2148 testMsg.map_string_string.set("f", "jkl;");
\r
2149 testMsg.map_string_enum.set("g", Enum.A);
\r
2150 testMsg.map_string_enum.set("h", Enum.B);
\r
2151 testMsg.map_int32_string.set(9, "a");
\r
2152 testMsg.map_int32_string.set(10, "b");
\r
2153 testMsg.map_int64_string.set("12345678901234", "a");
\r
2154 testMsg.map_int64_string.set("98765432109876", "b");
\r
2155 testMsg.map_bool_string.set(false, "a");
\r
2156 testMsg.map_bool_string.set(true, "b");
\r
2158 var jsonObj = JSON.parse(testMsg.encodeJSON());
\r
2159 test.deepEqual(jsonObj,
\r
2161 optional_int32: 1,
\r
2162 optional_int64: "12345678901234",
\r
2163 optional_string: "hello",
\r
2164 optional_bytes: "AP+A", // base64
\r
2165 optional_bool: true,
\r
2166 optional_enum: "A",
\r
2167 repeated_int32: [1],
\r
2168 repeated_int64: ["12345678901234"],
\r
2169 repeated_string: ["hello"],
\r
2170 repeated_bytes: ["AP+A"], // base64
\r
2171 repeated_bool: [true],
\r
2172 repeated_enum: ["A"],
\r
2173 map_string_int32: { "a": 1, "b": 2 },
\r
2174 map_string_int64: { "c": "12345678901234", "d": "98765432109876" },
\r
2175 map_string_string: { "e": "asdf", "f": "jkl;" },
\r
2176 map_string_enum: { "g": "A", "h": "B" },
\r
2177 map_int32_string: { "9": "a", "10": "b" },
\r
2178 map_int64_string: { "12345678901234": "a", "98765432109876": "b" },
\r
2179 map_bool_string: { "false": "a", "true": "b" },
\r
2182 var testMsg2 = Test.decodeJSON(testMsg.encodeJSON());
\r
2183 test.strictEqual(testMsg2.encodeJSON(), testMsg.encodeJSON());
\r
2189 "loaders": BROWSER ? {} : {
\r
2191 "commonjs": function(test) {
\r
2192 var fs = require("fs")
\r
2193 , vm = require("vm")
\r
2194 , util = require('util');
\r
2196 var code = fs.readFileSync(__dirname+"/../dist/"+FILE);
\r
2198 var sandbox = new Sandbox({
\r
2204 require: (function() {
\r
2205 function require(mod) {
\r
2206 if (mod == 'bytebuffer') require.called = true;
\r
2207 return ByteBuffer;
\r
2209 require.called = false;
\r
2213 vm.runInNewContext(code, sandbox, "ProtoBuf.js in CommonJS-VM");
\r
2214 // console.log(util.inspect(sandbox));
\r
2215 test.ok(typeof sandbox.module.exports == 'object');
\r
2216 test.ok(typeof sandbox.require != 'undefined' && sandbox.require.called);
\r
2220 "amd": function(test) {
\r
2221 var fs = require("fs")
\r
2222 , vm = require("vm")
\r
2223 , util = require('util');
\r
2225 var code = fs.readFileSync(__dirname+"/../dist/"+FILE);
\r
2226 var sandbox = new Sandbox({
\r
2227 define: (function() {
\r
2228 function define() {
\r
2229 define.called = true;
\r
2231 define.amd = true;
\r
2232 define.called = false;
\r
2236 vm.runInNewContext(code, sandbox, "ProtoBuf.js in AMD-VM");
\r
2237 // console.log(util.inspect(sandbox));
\r
2238 test.ok(sandbox.define.called == true);
\r
2242 "shim": function(test) {
\r
2243 var fs = require("fs")
\r
2244 , vm = require("vm")
\r
2245 , util = require('util');
\r
2247 var code = fs.readFileSync(__dirname+"/../dist/"+FILE);
\r
2248 var sandbox = new Sandbox({
\r
2250 ByteBuffer: ByteBuffer
\r
2253 vm.runInNewContext(code, sandbox, "ProtoBuf.js in shim-VM");
\r
2254 // console.log(util.inspect(sandbox));
\r
2255 test.ok(typeof sandbox.dcodeIO != 'undefined' && typeof sandbox.dcodeIO.ProtoBuf != 'undefined');
\r
2261 if (typeof module != 'undefined' && module.exports) {
\r
2262 module.exports = suite;
\r
2264 global["suite"] = suite;
\r