suite.js 92 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267
  1. /*
  2. Copyright 2013 Daniel Wirtz <dcode@dcode.io>
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. /**
  14. * ProtoBuf.js Test Suite.
  15. * @author Daniel Wirtz <dcode@dcode.io>
  16. */
  17. (function(global) {
  18. var FILE = "protobuf.js";
  19. var BROWSER = !!global.window;
  20. var StdOutFixture = require('fixture-stdout');
  21. var fixture = new StdOutFixture();
  22. var ProtoBuf = BROWSER ? global.dcodeIO.ProtoBuf : require(__dirname+"/../dist/"+FILE),
  23. ByteBuffer = BROWSER ? global.dcodeIO.ByteBuffer : ByteBuffer || require("bytebuffer"),
  24. util = BROWSER ? null : require("util"),
  25. fs = BROWSER ? null : require("fs");
  26. if (typeof __dirname == 'undefined') {
  27. __dirname = document.location.href.replace(/[\/\\][^\/\\]*$/, "");
  28. }
  29. /**
  30. * Constructs a new Sandbox for module loaders and shim testing.
  31. * @param {Object.<string,*>} properties Additional properties to set
  32. * @constructor
  33. */
  34. var Sandbox = function(properties) {
  35. this.ByteBuffer = function() {};
  36. for (var i in properties) {
  37. this[i] = properties[i];
  38. }
  39. this.console = {
  40. log: function(s) {
  41. console.log(s);
  42. }
  43. };
  44. };
  45. function fail(e) {
  46. throw(e);
  47. }
  48. /**
  49. * Validates the complexDotProto and complexInline tests.
  50. * @param {*} test Nodeunit test
  51. * @param {Object} Game Game namespace
  52. */
  53. function validateComplex(test, Game) {
  54. var Car = Game.Cars.Car,
  55. Vendor = Car.Vendor,
  56. Speed = Car.Speed;
  57. var vendor;
  58. // Car from class with argument list properties
  59. var car = new Car(
  60. "Rusty",
  61. // Vendor from class with object properties
  62. vendor = new Vendor({
  63. "name": "Iron Inc.",
  64. // Address from object
  65. "address": {
  66. "country": "US"
  67. },
  68. "models": ["m1"]
  69. }),
  70. // Speed from enum object
  71. Speed.SUPERFAST
  72. );
  73. test.equal(car.model, "Rusty");
  74. test.equal(car.vendor.name, "Iron Inc.");
  75. test.equal(car.vendor.address.country, "US");
  76. test.equal(car.vendor.address.country, car.getVendor().get_address().country);
  77. var bb = new ByteBuffer(32);
  78. car.encode(bb);
  79. 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>");
  80. var carDec = Car.decode(bb);
  81. test.equal(carDec.model, "Rusty");
  82. test.equal(carDec.vendor.name, "Iron Inc.");
  83. test.equal(carDec.vendor.address.country, "US");
  84. test.equal(carDec.vendor.address.country, carDec.getVendor().get_address().country);
  85. test.equal(carDec.vendor.models[0], "m1");
  86. }
  87. /**
  88. * Test suite.
  89. * @type {Object.<string,function>}
  90. */
  91. var suite = {
  92. "init": function(test) {
  93. test.ok(typeof ProtoBuf == "object");
  94. test.ok(typeof ProtoBuf.Reflect == 'object');
  95. test.ok(typeof ProtoBuf.loadProto == "function");
  96. test.ok(typeof ProtoBuf.loadProtoFile == "function");
  97. test.strictEqual(ProtoBuf.loadProto, ProtoBuf.protoFromString);
  98. test.strictEqual(ProtoBuf.loadProtoFile, ProtoBuf.protoFromFile);
  99. test.ok(ProtoBuf.ByteBuffer);
  100. test.done();
  101. },
  102. "IS_NODE": function(test) {
  103. test.ok(ProtoBuf.Util.IS_NODE);
  104. test.done();
  105. },
  106. // Example "A Simple Message" from the protobuf docs
  107. // https://developers.google.com/protocol-buffers/docs/encoding#simple
  108. "example1": function(test) {
  109. try{
  110. var builder = ProtoBuf.loadProtoFile(__dirname+"/example1.proto");
  111. var Test1 = builder.build("Test1");
  112. test.ok(typeof Test1 == 'function');
  113. var inst = new Test1(150);
  114. test.ok(inst instanceof ProtoBuf.Builder.Message);
  115. test.equal(inst.a, 150);
  116. test.equal(inst.getA(), 150);
  117. test.equal(inst.get_a(), 150);
  118. inst.setA(151);
  119. test.equal(inst.a, 151);
  120. test.equal(inst.getA(), 151);
  121. test.equal(inst.get_a(), 151);
  122. inst.set_a(152);
  123. test.equal(inst.a, 152);
  124. test.equal(inst.toString(), ".Test1");
  125. test.throws(function() {
  126. inst.setA(null); // required
  127. });
  128. test.throws(function() {
  129. inst.setA([]);
  130. });
  131. var size = inst.calculate();
  132. var bb = new ByteBuffer(3);
  133. inst.encode(bb);
  134. test.strictEqual(bb.offset, size);
  135. test.equal(bb.flip().toString("debug"), "<08 98 01>");
  136. var instDec = Test1.decode(bb);
  137. test.equal(instDec.a, 152);
  138. } catch (e) {
  139. fail(e);
  140. }
  141. test.done();
  142. },
  143. // Basically the same as example1, but with an unsigned value.
  144. "example1u": function(test) {
  145. try{
  146. var builder = ProtoBuf.loadProtoFile(__dirname+"/example1u.proto");
  147. var Test1u = builder.build("Test1u");
  148. test.ok(typeof Test1u == 'function');
  149. var inst = new Test1u(-1);
  150. test.strictEqual(inst.a, 4294967295);
  151. var bb = new ByteBuffer(6);
  152. var size = inst.calculate();
  153. inst.encode(bb);
  154. test.strictEqual(bb.offset, size);
  155. test.equal(bb.flip().toString("debug"), "<08 FF FF FF FF 0F>");
  156. var instDec = Test1u.decode(bb);
  157. test.strictEqual(instDec.a, 4294967295);
  158. } catch (e) {
  159. fail(e);
  160. }
  161. test.done();
  162. },
  163. // Example "Strings" from the protobuf docs
  164. // https://developers.google.com/protocol-buffers/docs/encoding#types
  165. "example2": function(test) {
  166. try {
  167. var builder = ProtoBuf.loadProtoFile(__dirname+"/example2.proto");
  168. var Test2 = builder.build("Test2");
  169. var inst = new Test2("testing");
  170. var bb = new ByteBuffer(9);
  171. var size = inst.calculate();
  172. inst.encode(bb);
  173. test.strictEqual(bb.offset, size);
  174. test.equal(bb.flip().toString("debug"), "<12 07 74 65 73 74 69 6E 67>");
  175. var instDec = Test2.decode(bb);
  176. test.equal(instDec.b, "testing");
  177. } catch (e) {
  178. fail(e);
  179. }
  180. test.done();
  181. },
  182. // Example "Embedded Messages" from the protobuf docs
  183. // https://developers.google.com/protocol-buffers/docs/encoding#embedded
  184. "example3": function(test) {
  185. try {
  186. var builder = ProtoBuf.loadProtoFile(__dirname+"/example3.proto");
  187. var root = builder.build();
  188. var Test1 = root.Test1;
  189. var Test3 = root.Test3;
  190. var inst = new Test3(new Test1(150));
  191. var bb = new ByteBuffer(5);
  192. test.equal(inst.c.a, 150);
  193. var size = inst.calculate();
  194. inst.encode(bb);
  195. test.strictEqual(bb.offset, size);
  196. test.equal(bb.flip().toString("debug"), "<1A 03 08 96 01>");
  197. var instDec = Test3.decode(bb);
  198. test.equal(instDec.c.a, 150);
  199. } catch(e) {
  200. fail(e);
  201. }
  202. test.done();
  203. },
  204. "example4": function(test) {
  205. try {
  206. var builder = ProtoBuf.loadProtoFile(__dirname+"/example4.proto");
  207. var Test4 = builder.build("Test4");
  208. var inst = new Test4([3, 270, 86942]);
  209. var bb = new ByteBuffer(8);
  210. test.equal(inst.d.length, 3);
  211. var size = inst.calculate();
  212. inst.encode(bb);
  213. test.strictEqual(bb.offset, size);
  214. test.equal(bb.flip().toString("debug"), "<22 06 03 8E 02 9E A7 05>");
  215. var instDec = Test4.decode(bb);
  216. test.equal(bb.toString("debug"), "22 06 03 8E 02 9E A7 05|");
  217. test.equal(instDec.d.length, 3);
  218. test.equal(instDec.d[2], 86942);
  219. } catch(e) {
  220. fail(e);
  221. }
  222. test.done();
  223. },
  224. "example5": function(test) {
  225. try {
  226. var builder = ProtoBuf.loadProtoFile(__dirname+"/example5.proto");
  227. builder.build();
  228. } catch(e) {
  229. fail(e);
  230. }
  231. test.done();
  232. },
  233. "constructor": function(test) {
  234. var builder = ProtoBuf.loadProtoFile(__dirname+"/example1.proto");
  235. var Test1 = builder.build("Test1");
  236. var t1 = new Test1(123),
  237. t2 = new Test1({a: 123}),
  238. t3 = new Test1(t1);
  239. test.deepEqual(t1, t2);
  240. test.deepEqual(t2, t3);
  241. test.done();
  242. },
  243. "constructorWithOneofs": function(test) {
  244. try {
  245. var builder = ProtoBuf.loadProtoFile(__dirname+"/oneof.proto"),
  246. MyOneOf = builder.build("MyOneOf"),
  247. TOneOf = builder.lookup(".MyOneOf");
  248. test.ok(TOneOf.getChild("my_oneof"));
  249. var myOneOf = new MyOneOf();
  250. test.strictEqual(myOneOf.my_oneof, null);
  251. myOneOf.set("id", 1);
  252. test.strictEqual(myOneOf.my_oneof, "id");
  253. myOneOf.set("name", "me");
  254. test.strictEqual(myOneOf.my_oneof, "name");
  255. test.strictEqual(myOneOf.id, null);
  256. var copy = new MyOneOf(myOneOf); // this line is what was failing
  257. // Error: .MyOneOf#my_oneof is not a field: undefined
  258. test.deepEqual(myOneOf, copy);
  259. // Test same things are there
  260. test.strictEqual(copy.my_oneof, "name");
  261. test.strictEqual(copy.name, "me");
  262. test.strictEqual(copy.id, null);
  263. } catch (e) {
  264. fail(e);
  265. }
  266. test.done();
  267. },
  268. "numberFormats": function(test) {
  269. try {
  270. var builder = ProtoBuf.loadProtoFile(__dirname+"/numberformats.proto");
  271. var Formats = builder.build("Formats");
  272. test.strictEqual(Formats.DEC, 1);
  273. test.strictEqual(Formats.HEX, 31);
  274. test.strictEqual(Formats.OCT, 15);
  275. var Msg = builder.build("Msg");
  276. var msg = new Msg();
  277. test.strictEqual(msg.dec, -1);
  278. test.strictEqual(msg.hex, -31);
  279. test.strictEqual(msg.hexUC, 521);
  280. test.strictEqual(msg.oct, -15);
  281. test.strictEqual(msg.exp, 0.1e5);
  282. test.strictEqual(msg.nod, 1.);
  283. test.strictEqual(msg.exn, 1e8);
  284. test.strictEqual(msg.sp1, Infinity);
  285. test.strictEqual(msg.sp2, -Infinity);
  286. test.ok(isNaN(msg.sp3));
  287. } catch (e) {
  288. fail(e);
  289. }
  290. test.done();
  291. },
  292. // Check encode/decode against a table of known correct pairs.
  293. // Note that javascript ArrayBuffer does not support signed Zero or NaN
  294. // bertdouglas (https://github.com/bertdouglas)
  295. "float": function(test) {
  296. try {
  297. var str_proto = "message Float {"
  298. + " required float f = 1;"
  299. + "}";
  300. var builder = ProtoBuf.loadProto(str_proto);
  301. var root = builder.build();
  302. var Float = root.Float;
  303. var in_tolerance = function (reference,actual) {
  304. var tol = 1e-6;
  305. var scale = 1.0;
  306. if (reference != 0.0 ) {
  307. scale = reference;
  308. };
  309. var err = Math.abs(reference - actual)/scale;
  310. return err < tol;
  311. };
  312. var f_vals = [
  313. // hex values are shown here in big-endian following IEEE754 notation
  314. // protobuf is little-endian
  315. // { f: -0.0 , b: "80 00 00 00" },
  316. { f: +0.0 , b: "00 00 00 00" },
  317. { f: -1e-10 , b: "AE DB E6 FF" },
  318. { f: +1e-10 , b: "2E DB E6 FF" },
  319. { f: -2e+10 , b: "D0 95 02 F9" },
  320. { f: +2e+10 , b: "50 95 02 F9" },
  321. { f: -3e-30 , b: "8E 73 63 90" },
  322. { f: +3e-30 , b: "0E 73 63 90" },
  323. { f: -4e+30 , b: "F2 49 F2 CA" },
  324. { f: +4e+30 , b: "72 49 F2 CA" },
  325. { f: -123456789.0 , b: "CC EB 79 A3" },
  326. { f: +123456789.0 , b: "4C EB 79 A3" },
  327. { f: -0.987654321 , b: "BF 7C D6 EA" },
  328. { f: +0.987654321 , b: "3F 7C D6 EA" },
  329. { f: -Infinity , b: "FF 80 00 00" },
  330. { f: +Infinity , b: "7F 80 00 00" }
  331. // { f: -NaN , b: "FF C0 00 00>" },
  332. // { f: +NaN , b: "7F C0 00 00" }
  333. ];
  334. f_vals.map( function(x) {
  335. // check encode
  336. var m1 = new Float();
  337. var b1 = new ByteBuffer();
  338. m1.f = x.f;
  339. m1.encode(b1);
  340. var q1 = b1.slice(1,5).compact().reverse();
  341. test.strictEqual('<' + x.b + '>', q1.toString("debug"));
  342. // check decode
  343. var b2 = new ByteBuffer();
  344. var s1 = x.b + ' 0D';
  345. var s2 = s1.split(" ");
  346. var s3 = s2.reverse();
  347. var i1 = s3.map(function(y) { return parseInt(y,16) } );
  348. i1.map(function(y) { b2.writeUint8(y) });
  349. b2.limit = b2.offset;
  350. b2.offset = 0;
  351. var m2 = Float.decode(b2);
  352. var s4 = "" + x.f +" " + m2.f;
  353. if ( isNaN(x.f) ) {
  354. test.ok( isNaN(m2.f), s4 );
  355. }
  356. else if ( ! isFinite( x.f) ) {
  357. test.ok( x.f === m2.f, s4 );
  358. }
  359. else {
  360. test.ok( in_tolerance(x.f, m2.f), s4 );
  361. }
  362. });
  363. } catch(e) {
  364. fail(e);
  365. }
  366. test.done();
  367. },
  368. "bytes": function(test) {
  369. try {
  370. var str_proto = "message Test { required bytes b = 1; }";
  371. var builder = ProtoBuf.loadProto(str_proto);
  372. var Test = builder.build("Test");
  373. var bb = new ByteBuffer(4).writeUint32(0x12345678).flip();
  374. var myTest = new Test(bb);
  375. test.strictEqual(myTest.b.array, bb.array);
  376. var bb2 = new ByteBuffer(6);
  377. var size = myTest.calculate();
  378. myTest.encode(bb2);
  379. test.strictEqual(bb2.offset, size);
  380. test.equal(bb2.flip().toString("debug"), "<0A 04 12 34 56 78>");
  381. myTest = Test.decode(bb2);
  382. test.equal(myTest.b.BE().readUint32(), 0x12345678);
  383. } catch (e) {
  384. fail(e);
  385. }
  386. test.done();
  387. },
  388. "bytesFromFile": function(test) {
  389. try {
  390. var builder = ProtoBuf.loadProto("message Image { required bytes data = 1; }"),
  391. Image = builder.build("Image"),
  392. data = fs.readFileSync(__dirname+"/../protobuf.png"),
  393. image = new Image({ data: data }),
  394. bb = image.encode(),
  395. imageDec = Image.decode(bb),
  396. dataDec = imageDec.data.toBuffer();
  397. test.strictEqual(data.length, dataDec.length);
  398. test.deepEqual(data, dataDec);
  399. } catch (e) {
  400. fail(e);
  401. }
  402. test.done();
  403. },
  404. "notEnoughBytes": function(test) {
  405. var builder = ProtoBuf.loadProto("message Test { required bytes b = 1; }");
  406. var Test = builder.build("Test");
  407. var bb = new ByteBuffer().writeUint32(0x12345678).flip();
  408. var encoded = new ByteBuffer(6);
  409. new Test(bb).encode(encoded);
  410. test.equal(encoded.flip().toString("debug"), "<0A 04 12 34 56 78>");
  411. encoded = encoded.slice(0, 5); // chop off the last byte
  412. var err = null;
  413. try {
  414. Test.decode(encoded);
  415. } catch (caught) {
  416. err = caught;
  417. }
  418. test.ok(err && err.message && err.message.indexOf(": 4 required but got only 3") >= 0);
  419. test.done();
  420. },
  421. "bool": function(test) {
  422. try {
  423. var builder = ProtoBuf.loadProto("message Test { optional bool ok = 1 [ default = false ]; }"),
  424. Test = builder.build("Test"),
  425. t = new Test();
  426. test.strictEqual(t.ok, null); // Not set as it is optional
  427. t.setOk(true);
  428. test.strictEqual(t.ok, true);
  429. test.strictEqual(Test.decode(t.encode()).ok, true);
  430. t.setOk(false);
  431. test.strictEqual(t.ok, false);
  432. t.setOk(null); // Not set
  433. test.strictEqual(Test.decode(t.encode()).ok, false); // = default when missing
  434. } catch (err) {
  435. fail(err);
  436. }
  437. test.done();
  438. },
  439. // As mentioned by Bill Katz
  440. "T139": function(test) {
  441. try{
  442. var builder = ProtoBuf.loadProtoFile(__dirname+"/T139.proto");
  443. var T139 = builder.build("T139");
  444. test.ok(typeof T139 == 'function');
  445. var inst = new T139(139,139);
  446. test.equal(inst.a, 139);
  447. test.equal(inst.b, 139);
  448. inst.setA(139);
  449. inst.setB(139);
  450. test.equal(inst.a, 139);
  451. test.equal(inst.b, 139);
  452. var bb = new ByteBuffer(3);
  453. inst.encode(bb);
  454. test.equal(bb.flip().toString("debug"), "<08 8B 01 10 8B 01>");
  455. var instDec = T139.decode(bb);
  456. test.equal(instDec.a, 139);
  457. test.equal(instDec.b, 139);
  458. } catch (e) {
  459. fail(e);
  460. }
  461. test.done();
  462. },
  463. "emptyDefaultString": function(test) {
  464. try {
  465. var builder = ProtoBuf.loadProto("message Test1 { required string test = 1 [default = \"\"]; }");
  466. var Test1;
  467. test.doesNotThrow(function() {
  468. Test1 = builder.build("Test1");
  469. });
  470. var test1 = new Test1();
  471. test.strictEqual(test1.test, "");
  472. } catch (e) {
  473. fail(e);
  474. }
  475. test.done();
  476. },
  477. "trailingSemicolon": function(test) {
  478. try {
  479. var builder = ProtoBuf.loadProto("message Test1 { optional string test = 1; };");
  480. test.doesNotThrow(function() {
  481. var Test1 = builder.build("Test1");
  482. });
  483. } catch (e) {
  484. fail(e);
  485. }
  486. test.done();
  487. },
  488. "inner": {
  489. "longstr": function(test) {
  490. try {
  491. var builder = ProtoBuf.loadProto("message Test { required Inner a = 1; message Inner { required string b = 1; } }");
  492. var Test = builder.build("Test");
  493. var t = new Test();
  494. var data = "0123456789"; // 10: 20, 40, 80, 160, 320 bytes
  495. for (var i=0; i<5; i++) data += data;
  496. test.equal(data.length, 320);
  497. t.a = new Test.Inner(data);
  498. var bb = t.encode();
  499. var t2 = Test.decode(bb);
  500. test.equal(t2.a.b.length, 320);
  501. test.equal(data, t2.a.b);
  502. } catch (e) {
  503. fail(e);
  504. }
  505. test.done();
  506. },
  507. "multiple": function(test) {
  508. try {
  509. var str = "";
  510. for (var i=0; i<200; i++) str += 'a';
  511. var builder = ProtoBuf.loadProtoFile(__dirname+"/inner.proto");
  512. var fooCls = builder.build("Foo");
  513. var barCls = builder.build("Bar");
  514. var bazCls = builder.build("Baz");
  515. var foo = new fooCls(new barCls(str), new bazCls(str));
  516. var fooEncoded = foo.encode();
  517. test.doesNotThrow(function() {
  518. fooCls.decode(fooEncoded);
  519. });
  520. } catch (e) {
  521. fail(e);
  522. }
  523. test.done();
  524. },
  525. "float": function(test) {
  526. try {
  527. var builder = ProtoBuf.loadProto("message Foo { required Bar bar = 1; } message Bar { required float baz = 1; }");
  528. var root = builder.build();
  529. var foo = new root.Foo(new root.Bar(4));
  530. var bb = foo.encode();
  531. var foo2 = root.Foo.decode(bb);
  532. test.equal(foo.bar.baz, 4);
  533. test.equal(foo2.bar.baz, foo.bar.baz);
  534. } catch (e) {
  535. fail(e);
  536. }
  537. test.done();
  538. }
  539. },
  540. "truncated": function(test) {
  541. try {
  542. var builder = ProtoBuf.loadProto("message Test { required int32 a = 1; required int32 b = 2; }");
  543. var Test = builder.build("Test");
  544. var t = new Test(), bb = new ByteBuffer(2);
  545. t.setA(1);
  546. try {
  547. bb = t.encode(bb).flip();
  548. test.ok(false);
  549. } catch (e) {
  550. test.ok(e.encoded);
  551. bb = e.encoded.flip();
  552. test.equal(bb.toString("debug"), "<08 01>");
  553. }
  554. var t2;
  555. try /* to decode truncated message */ {
  556. t2 = Test.decode(bb);
  557. test.ok(false); // ^ throws
  558. } catch (e) {
  559. // But still be able to access the rest
  560. var t3 = e.decoded;
  561. test.strictEqual(t3.a, 1);
  562. test.strictEqual(t3.b, null);
  563. }
  564. test.strictEqual(t2, undefined);
  565. } catch (e) {
  566. fail(e);
  567. }
  568. test.done();
  569. },
  570. // Options on all levels
  571. "options": {
  572. "parse": function(test) {
  573. try {
  574. var parser = new ProtoBuf.DotProto.Parser(ProtoBuf.Util.fetch(__dirname+"/options.proto"));
  575. var root = parser.parse();
  576. test.equal(root["package"], "My");
  577. test.strictEqual(root["options"]["(toplevel_1)"], 10);
  578. test.equal(root["options"]["(toplevel_2)"], "Hello world!");
  579. var opt = root["messages"][0]["fields"][0]["options"];
  580. test.equal(opt["default"], "Max");
  581. opt = root["messages"][0]["options"];
  582. test.strictEqual(opt["(inmessage)"], "My.Test");
  583. test.strictEqual(opt["(foo.my_option).bar"], false);
  584. opt = root["messages"][0]["fields"][1]["options"];
  585. test.strictEqual(opt["default"], "Shouldn't mix quotes");
  586. opt = root["messages"][0]["fields"][2]["options"];
  587. test.strictEqual(opt["default"], 'Shouldn"t mix quotes');
  588. opt = root["messages"][0]["fields"][3]["options"];
  589. test.strictEqual(opt["(foo_options).opt1"], 123);
  590. test.strictEqual(opt["(foo_options).opt2"], "baz");
  591. } catch (e) {
  592. fail(e);
  593. }
  594. test.done();
  595. },
  596. "export": function(test) {
  597. try {
  598. var builder = ProtoBuf.loadProtoFile(__dirname+"/options.proto");
  599. var My = builder.build("My");
  600. test.deepEqual(My.$options, {
  601. "(toplevel_1)": 10,
  602. "(toplevel_2)": "Hello world!"
  603. });
  604. test.strictEqual(My.$options['(toplevel_1)'], 10);
  605. test.deepEqual(My.Test.$options, {
  606. "(inmessage)": "My.Test",
  607. "(foo.my_option).bar": false
  608. });
  609. } catch (e) {
  610. fail(e);
  611. }
  612. test.done();
  613. }
  614. },
  615. // Comments
  616. "comments": function(test) {
  617. try {
  618. var tn = new ProtoBuf.DotProto.Tokenizer(ProtoBuf.Util.fetch(__dirname+'/comments.proto'));
  619. var token, tokens = [];
  620. do {
  621. token = tn.next();
  622. tokens.push(token);
  623. } while (token !== null);
  624. test.deepEqual(tokens, ['message', 'TestC', '{', 'required', 'int32', 'a', '=', '1', ';', '}', null]);
  625. } catch (e) {
  626. fail(e);
  627. }
  628. test.done();
  629. },
  630. // A more or less complex proto with type references
  631. "complexProto": function(test) {
  632. try {
  633. var builder = ProtoBuf.loadProtoFile(__dirname+"/complex.proto");
  634. validateComplex(test, builder.build("Game"));
  635. var TCars = builder.lookup("Game.Cars");
  636. test.strictEqual(TCars.fqn(), ".Game.Cars");
  637. } catch(e) {
  638. fail(e);
  639. }
  640. test.done();
  641. },
  642. // The same created without calling upon the parser to do so
  643. "complexJSON": function(test) {
  644. try {
  645. var builder = ProtoBuf.loadJsonFile(__dirname+"/complex.json");
  646. validateComplex(test, builder.build("Game"));
  647. } catch (e) {
  648. fail(e);
  649. }
  650. test.done();
  651. },
  652. // Test error messages
  653. "errorMessage": function(test) {
  654. test.throws(function() {
  655. var builder = ProtoBuf.loadJsonFile(__dirname+"/complex.json");
  656. var Game = builder.build("Game");
  657. var car = new Game.Cars.Car();
  658. car.speed = "hello";
  659. car.encode();
  660. }, /Illegal value for speed/);
  661. test.done();
  662. },
  663. // Builder reused to add definitions from multiple sources
  664. "multiBuilder": function(test) {
  665. try {
  666. var builder = ProtoBuf.loadProtoFile(__dirname+"/example1.proto");
  667. ProtoBuf.loadProtoFile(__dirname+"/example2.proto", builder);
  668. var ns = builder.build();
  669. test.ok(!!ns.Test1);
  670. test.ok(!!ns.Test2);
  671. } catch (e) {
  672. fail(e);
  673. }
  674. test.done();
  675. },
  676. // Inner messages test
  677. "inner": function(test) {
  678. try {
  679. var builder = ProtoBuf.loadProtoFile(__dirname+"/repeated.proto");
  680. var root = builder.build(),
  681. Outer = root.Outer,
  682. Inner = root.Inner;
  683. // Empty
  684. var outer = new Outer();
  685. var bb = new ByteBuffer(1).fill(0).flip();
  686. outer.encode(bb);
  687. test.equal(bb.flip().toString("debug"), "|00");
  688. var douter = Outer.decode(bb);
  689. test.ok(douter.inner instanceof Array);
  690. test.equal(douter.inner.length, 0);
  691. // Multiple
  692. outer = new Outer({ inner: [new Inner(1), new Inner(2)] });
  693. bb = new ByteBuffer(8);
  694. var size = outer.calculate();
  695. outer.encode(bb);
  696. test.strictEqual(bb.offset, size);
  697. test.equal(bb.flip().toString("debug"), "<0A 02 08 01 0A 02 08 02>");
  698. douter = Outer.decode(bb);
  699. test.ok(douter.inner instanceof Array);
  700. test.equal(douter.inner.length, 2);
  701. test.equal(douter.inner[0].inner_value, 1);
  702. test.equal(douter.inner[1].inner_value, 2);
  703. } catch (e) {
  704. fail(e);
  705. }
  706. test.done();
  707. },
  708. // Packed vs. not packed repeated fields test
  709. "packed": function(test) {
  710. try {
  711. var builder = ProtoBuf.loadProtoFile(__dirname+"/packed.proto");
  712. var Message = builder.build("Message");
  713. // Both empty
  714. var message = new Message();
  715. var bb = new ByteBuffer(1).fill(0).flip();
  716. var size = message.calculate();
  717. message.encode(bb);
  718. test.strictEqual(bb.offset, size);
  719. test.equal(bb.flip().toString("debug"), "|00");
  720. message = Message.decode(bb);
  721. test.ok(message.a instanceof Array);
  722. test.equal(message.a.length, 0);
  723. test.ok(message.b instanceof Array);
  724. test.equal(message.b.length, 0);
  725. // Both non-empty
  726. message = new Message([1,2,3], [1,2,3]);
  727. size = message.calculate();
  728. message.encode(bb.resize(11));
  729. test.strictEqual(bb.offset, size);
  730. test.equal(bb.flip().toString("debug"), "<0A 03 01 02 03 10 01 10 02 10 03>");
  731. message = Message.decode(bb);
  732. test.ok(message.a instanceof Array);
  733. test.equal(message.a.length, 3);
  734. test.deepEqual(message.a, [1,2,3]);
  735. test.ok(message.b instanceof Array);
  736. test.equal(message.b.length, 3);
  737. test.deepEqual(message.b, [1,2,3]);
  738. } catch (e) {
  739. fail(e);
  740. }
  741. test.done();
  742. },
  743. // Legacy groups test
  744. "groups": function(test) {
  745. try {
  746. var builder = ProtoBuf.loadProtoFile(__dirname+"/groups.proto");
  747. var root = builder.build();
  748. var Outer = root.Outer;
  749. var TOuter = builder.ns.getChild("Outer");
  750. var TInner = TOuter.getChild("MyInner");
  751. test.ok(TInner instanceof ProtoBuf.Reflect.Message);
  752. test.strictEqual(TInner.isGroup, true);
  753. var Tinner = TOuter.getChild("myinner");
  754. test.ok(Tinner instanceof ProtoBuf.Reflect.Message.Field);
  755. test.strictEqual(Tinner.id, 2);
  756. test.deepEqual(Tinner.options, { "deprecated": true });
  757. var Inner = root.Outer.MyInner;
  758. var outer = new Outer("a", [new Inner("hello")], "b", new Inner("world"));
  759. var bb = new ByteBuffer();
  760. var size = outer.calculate();
  761. outer.encode(bb);
  762. test.strictEqual(bb.offset, size);
  763. bb.flip().compact();
  764. var wiredMsg = [
  765. "0A", // 1|010 = id 1, wire type 2 (ldelim)
  766. "01", // length 1
  767. "61", // "a"
  768. "13", // 10|011 = id 2, wire type 3 (start group)
  769. "1A", // 11|010 = id 3, wire type 2 (ldelim)
  770. "05", // length 5
  771. "68 65 6C 6C 6F", // "hello"
  772. "14", // 10|100 = id 2, wire type 4 (end group)
  773. "22", // 100|010 = id 4, wire type 2 (ldelim)
  774. "01", // length 1
  775. "62", // "b"
  776. "2B", // 101|011 = id 5, wire type = 3 (start group)
  777. "1A", // 11|010 = id 3, wire type = 2 (ldelim)
  778. "05", // length 5
  779. "77 6F 72 6C 64", // "world"
  780. "2C" // 101|100 = id 5, wire type = 4 (end group)
  781. ];
  782. test.equal(bb.toString("debug"), "<" +wiredMsg.join(" ") + ">");
  783. var douter = Outer.decode(bb);
  784. test.strictEqual(douter.before, "a");
  785. test.strictEqual(douter.myinner.length, 1);
  786. test.strictEqual(douter.myinner[0].a, "hello");
  787. test.strictEqual(douter.after, "b");
  788. bb.offset = 0;
  789. douter = root.OuterSparse.decode(bb);
  790. test.strictEqual(bb.offset, bb.limit);
  791. test.strictEqual(douter.before, "a");
  792. test.strictEqual(douter.after, "b");
  793. } catch (e) {
  794. fail(e);
  795. }
  796. test.done();
  797. },
  798. "x64Fixed": function(test) {
  799. try {
  800. var builder = ProtoBuf.loadProtoFile(__dirname+"/x64.proto");
  801. var Test = builder.build("Test");
  802. var myTest = new Test();
  803. test.ok(myTest.val instanceof ByteBuffer.Long);
  804. test.equal(myTest.val.unsigned, false);
  805. test.equal(myTest.val.toNumber(), -1);
  806. test.ok(myTest.uval instanceof ByteBuffer.Long);
  807. test.equal(myTest.uval.unsigned, true);
  808. test.equal(myTest.uval.toNumber(), 1);
  809. myTest.setVal(-2);
  810. myTest.setUval(2);
  811. var bb = new ByteBuffer(18); // 2x tag + 2x 64bit
  812. var size = myTest.calculate();
  813. myTest.encode(bb);
  814. test.strictEqual(bb.offset, size);
  815. test.equal(bb.flip().toString("debug"), "<09 FE FF FF FF FF FF FF FF 11 02 00 00 00 00 00 00 00>");
  816. // ^ wireType=1, id=1 ^ wireType=1, id=2
  817. myTest = Test.decode(bb);
  818. test.ok(myTest.val instanceof ByteBuffer.Long);
  819. test.equal(myTest.val.unsigned, false);
  820. test.equal(myTest.val.toNumber(), -2);
  821. test.ok(myTest.uval instanceof ByteBuffer.Long);
  822. test.equal(myTest.uval.unsigned, true);
  823. test.equal(myTest.uval.toNumber(), 2);
  824. } catch (e) {
  825. fail(e);
  826. }
  827. test.done();
  828. },
  829. "x64Varint": function(test) {
  830. try {
  831. var builder = ProtoBuf.loadProtoFile(__dirname+"/x64.proto");
  832. var Test = builder.build("Test2");
  833. var Test = builder.build("Test2");
  834. var myTest = new Test();
  835. test.ok(myTest.val instanceof ByteBuffer.Long);
  836. test.equal(myTest.val.unsigned, false);
  837. test.equal(myTest.val.toNumber(), -1);
  838. test.ok(myTest.uval instanceof ByteBuffer.Long);
  839. test.equal(myTest.uval.unsigned, true);
  840. test.equal(myTest.uval.toNumber(), 1);
  841. test.ok(myTest.sval instanceof ByteBuffer.Long);
  842. test.equal(myTest.sval.unsigned, false);
  843. test.equal(myTest.sval.toNumber(), -2);
  844. myTest.setVal(-2);
  845. myTest.setUval(2);
  846. myTest.setSval(-3);
  847. var bb = new ByteBuffer(3+10+2); // 3x tag + 1x varint 10byte + 2x varint 1byte
  848. var size = myTest.calculate();
  849. myTest.encode(bb);
  850. test.strictEqual(bb.offset, size);
  851. test.equal(bb.flip().toString("debug"), "<08 FE FF FF FF FF FF FF FF FF 01 10 02 18 05>");
  852. // 08: wireType=0, id=1, 18: wireType=0, id=2, ?: wireType=0, id=3
  853. myTest = Test.decode(bb);
  854. test.ok(myTest.val instanceof ByteBuffer.Long);
  855. test.equal(myTest.val.unsigned, false);
  856. test.equal(myTest.val.toNumber(), -2);
  857. test.ok(myTest.uval instanceof ByteBuffer.Long);
  858. test.equal(myTest.uval.unsigned, true);
  859. test.equal(myTest.uval.toNumber(), 2);
  860. test.ok(myTest.sval instanceof ByteBuffer.Long);
  861. test.equal(myTest.sval.unsigned, false);
  862. test.equal(myTest.sval.toNumber(), -3);
  863. } catch (e) {
  864. fail(e);
  865. }
  866. test.done();
  867. },
  868. "keywords": function(test) {
  869. try {
  870. var builder = ProtoBuf.loadProto("message Reserved { optional string get = 1; }");
  871. var My = builder.build();
  872. var myTest = new My.Reserved("a");
  873. test.doesNotThrow(function() {
  874. myTest.encode();
  875. });
  876. } catch (e) {
  877. fail(e);
  878. }
  879. test.done();
  880. },
  881. "imports": function(test) {
  882. try {
  883. var builder = ProtoBuf.loadProtoFile(__dirname+"/imports.proto");
  884. var root = builder.build();
  885. test.ok(!!root.Test1);
  886. test.ok(!!root.Test2);
  887. test.ok(!!root.My.Test3);
  888. test.notEqual(root.Test2, root.My.Test2);
  889. } catch (e) {
  890. fail(e);
  891. }
  892. test.done();
  893. },
  894. "weakImports": function(test) {
  895. try {
  896. var builder = ProtoBuf.loadProtoFile(__dirname+"/imports-weak.proto");
  897. var root = builder.build();
  898. } catch (e) {
  899. test.ok(e.message.indexOf("unresolvable type reference") >= 0);
  900. test.done();
  901. return;
  902. }
  903. var e = new Error("Weak import was imported.");
  904. fail(e);
  905. },
  906. "importExtensions": function(test) {
  907. var x = "package x; \
  908. message Test { \
  909. extensions 1 to 10; \
  910. } \
  911. extend Test { \
  912. optional int32 first_val = 1; \
  913. }";
  914. var y = "package y; \
  915. extend x.Test { \
  916. optional int32 second_val = 2; \
  917. }";
  918. var builder = ProtoBuf.newBuilder();
  919. ProtoBuf.loadProto(x, builder);
  920. ProtoBuf.loadProto(y, builder);
  921. var Test = builder.build('x.Test');
  922. var inst = new Test();
  923. test.strictEqual(inst[".x.first_val"], null);
  924. test.strictEqual(inst[".y.second_val"], null);
  925. test.done();
  926. },
  927. "toplevel": function(test) {
  928. try {
  929. var builder = ProtoBuf.loadProtoFile(__dirname+"/toplevel.proto");
  930. var My = builder.build("My");
  931. test.ok(!!My.MyEnum);
  932. test.equal(My.MyEnum.ONE, 1);
  933. test.equal(My.MyEnum.TWO, 2);
  934. test.ok(!!My.Test);
  935. var myTest = new My.Test();
  936. test.equal(myTest.num, My.MyEnum.ONE);
  937. } catch (e) {
  938. fail(e);
  939. }
  940. test.done();
  941. },
  942. "importsToplevel": function(test) {
  943. try {
  944. var builder = ProtoBuf.loadProtoFile(__dirname+"/imports-toplevel.proto");
  945. var My = builder.build("My");
  946. test.ok(!!My.MyEnum);
  947. test.equal(My.MyEnum1.ONE, 1);
  948. test.equal(My.MyEnum1.TWO, 2);
  949. test.ok(!!My.Test1);
  950. var myTest = new My.Test1();
  951. test.equal(myTest.num, My.MyEnum.ONE);
  952. test.equal(myTest.num1, My.MyEnum1.ONE);
  953. } catch (e) {
  954. fail(e);
  955. }
  956. test.done();
  957. },
  958. "importDuplicate": function(test) {
  959. try {
  960. var builder = ProtoBuf.loadProtoFile(__dirname+"/import_a.proto");
  961. test.doesNotThrow(function() {
  962. ProtoBuf.loadProtoFile(__dirname+"/import_b.proto", builder);
  963. });
  964. var root = builder.build();
  965. test.ok(root.A);
  966. test.ok(root.B);
  967. test.ok(root.Common);
  968. } catch (e) {
  969. fail(e);
  970. }
  971. test.done();
  972. },
  973. "importDuplicateDifferentBuilder": function(test) {
  974. try {
  975. var builderA = ProtoBuf.loadProtoFile(__dirname+"/import_a.proto");
  976. var builderB;
  977. test.doesNotThrow(function() {
  978. builderB = ProtoBuf.loadProtoFile(__dirname+"/import_b.proto");
  979. });
  980. var rootA = builderA.build();
  981. var rootB = builderB.build();
  982. test.ok(rootA.A);
  983. test.ok(rootB.B);
  984. test.ok(rootA.Common);
  985. test.ok(rootB.Common);
  986. } catch (e) {
  987. fail(e);
  988. }
  989. test.done();
  990. },
  991. "dupimport": function(test) {
  992. try {
  993. // Suppress logging result to stdout
  994. fixture.capture(function() { return false;});
  995. require(__dirname+"/../cli/pbjs.js").main(["node", "bin/pbjs", __dirname+"/dupimport/main.proto", "--quiet"]);
  996. fixture.release();
  997. } catch (e) {
  998. fixture.release();
  999. fail(e);
  1000. }
  1001. test.done();
  1002. },
  1003. "field_name_same_as_package": function(test) {
  1004. try {
  1005. fixture.capture(function() { return false;});
  1006. require(__dirname+"/../cli/pbjs.js").main(["node", "bin/pbjs", __dirname+"/field_name_same_as_package/main.proto", "--quiet"]);
  1007. fixture.release();
  1008. } catch (e) {
  1009. fixture.release();
  1010. fail(e);
  1011. }
  1012. test.done();
  1013. },
  1014. "importRoot": function(test) {
  1015. try {
  1016. var builder = ProtoBuf.loadProtoFile({
  1017. root: __dirname,
  1018. file: "importRoot/file1.proto"
  1019. });
  1020. var Test = builder.build("Test");
  1021. test.ok(new Test() instanceof ProtoBuf.Builder.Message);
  1022. } catch (e) {
  1023. fail(e);
  1024. }
  1025. test.done();
  1026. },
  1027. "extend": function(test) {
  1028. try {
  1029. var ast = new ProtoBuf.DotProto.Parser(fs.readFileSync(__dirname+"/extend.proto")).parse();
  1030. test.deepEqual(ast, { package: null,
  1031. messages:
  1032. [ { ref: 'google.protobuf.MessageOptions',
  1033. fields:
  1034. [ { rule: 'optional',
  1035. type: 'int32',
  1036. name: 'foo',
  1037. options: {},
  1038. id: 1001 } ] },
  1039. { name: 'Foo',
  1040. fields: [],
  1041. enums: [],
  1042. messages: [],
  1043. options: {},
  1044. services: [],
  1045. oneofs: {},
  1046. extensions: [ [ 2, 536870911 ] ] },
  1047. { ref: 'Foo',
  1048. fields:
  1049. [ { rule: 'optional',
  1050. type: 'string',
  1051. name: 'bar',
  1052. options: {},
  1053. id: 2 } ] },
  1054. { name: 'Bar',
  1055. fields: [],
  1056. enums: [],
  1057. messages:
  1058. [ { name: 'Foo',
  1059. fields: [],
  1060. enums: [],
  1061. messages: [],
  1062. options: {},
  1063. services: [],
  1064. oneofs: {} },
  1065. { ref: '.Foo',
  1066. fields: [ { rule: 'optional', type: 'Foo', name: 'foo', options: {}, id: 3 } ] } ],
  1067. options: {},
  1068. services: [],
  1069. oneofs: {} } ],
  1070. enums: [],
  1071. imports: [ 'google/protobuf/descriptor.proto' ],
  1072. options: {},
  1073. services: [] }
  1074. );
  1075. var builder = ProtoBuf.loadProtoFile(__dirname+"/extend.proto");
  1076. var TFoo = builder.lookup(".Foo"),
  1077. TBar = builder.lookup(".Bar"),
  1078. TBarFoo = builder.lookup(".Bar.Foo"),
  1079. fields = TFoo.getChildren(ProtoBuf.Reflect.Message.Field);
  1080. test.strictEqual(fields.length, 2);
  1081. test.strictEqual(fields[0].name, ".bar");
  1082. test.strictEqual(fields[0].id, 2);
  1083. test.strictEqual(fields[1].name, ".Bar.foo");
  1084. test.strictEqual(fields[1].id, 3);
  1085. test.deepEqual(TFoo.extensions, [[2, ProtoBuf.ID_MAX]]); // explicitly defined
  1086. test.strictEqual(TBar.extensions, undefined); // none defined
  1087. test.deepEqual(TBar.getChild("foo"), { builder: builder, parent: TBar, name: "foo", field: TFoo.getChild('.Bar.foo') });
  1088. test.strictEqual(TBar.getChildren(ProtoBuf.Reflect.Message.Field).length, 0);
  1089. var root = builder.build();
  1090. test.strictEqual(TFoo.getChild(".Bar.foo").resolvedType, TBarFoo); // .Bar.Foo, not .Foo
  1091. var foo = new root.Foo(),
  1092. bar = new root.Bar();
  1093. foo['.bar'] = "123";
  1094. foo['.Bar.foo'] = bar;
  1095. test.equal(foo.encode().compact().toString("debug"), "<12 03 31 32 33 1A 00>");
  1096. } catch (e) {
  1097. fail(e);
  1098. }
  1099. test.done();
  1100. },
  1101. // Custom options on all levels
  1102. // victorr (https://github.com/victorr)
  1103. "customOptions": function(test) {
  1104. try {
  1105. var parser = new ProtoBuf.DotProto.Parser(ProtoBuf.Util.fetch(__dirname+"/custom-options.proto"));
  1106. var root = parser.parse();
  1107. test.equal(root["options"]["(my_file_option)"], "Hello world!");
  1108. test.equal(root["messages"][7]["options"]["(my_message_option)"], 1234);
  1109. test.equal(root["messages"][7]["fields"][0]["options"]["(my_field_option)"], 4.5);
  1110. // test.equal(root["services"]["MyService"]["options"]["my_service_option"], "FOO");
  1111. // TODO: add tests for my_enum_option, my_enum_value_option
  1112. } catch (e) {
  1113. fail(e);
  1114. }
  1115. test.done();
  1116. },
  1117. "oneofs": function(test) {
  1118. try {
  1119. var builder = ProtoBuf.loadProtoFile(__dirname+"/oneof.proto"),
  1120. MyOneOf = builder.build("MyOneOf"),
  1121. TOneOf = builder.lookup(".MyOneOf");
  1122. test.ok(TOneOf.getChild("my_oneof"));
  1123. var myOneOf = new MyOneOf();
  1124. test.strictEqual(myOneOf.my_oneof, null);
  1125. myOneOf.set("id", 1);
  1126. test.strictEqual(myOneOf.my_oneof, "id");
  1127. myOneOf.set("name", "me");
  1128. test.strictEqual(myOneOf.my_oneof, "name");
  1129. test.strictEqual(myOneOf.id, null);
  1130. var bb = myOneOf.encode().compact();
  1131. test.strictEqual(bb.toString("debug"), "<12 02 6D 65>"); // id 2, wt 2, len 2
  1132. myOneOf = MyOneOf.decode(bb);
  1133. test.strictEqual(myOneOf.my_oneof, "name");
  1134. test.strictEqual(myOneOf.name, "me");
  1135. test.strictEqual(myOneOf.id, null);
  1136. } catch (e) {
  1137. fail(e);
  1138. }
  1139. test.done();
  1140. },
  1141. "services": function(test) {
  1142. try {
  1143. var parser = new ProtoBuf.DotProto.Parser(ProtoBuf.Util.fetch(__dirname+"/custom-options.proto"));
  1144. var root = parser.parse();
  1145. test.deepEqual(root["services"], [{
  1146. "name": "MyService",
  1147. "rpc": {
  1148. "MyMethod": {
  1149. "request": "RequestType",
  1150. "response": "ResponseType",
  1151. "request_stream": false,
  1152. "response_stream": false,
  1153. "options": {
  1154. "(my_method_option).foo": 567,
  1155. "(my_method_option).bar": "Some string"
  1156. }
  1157. }
  1158. },
  1159. "options": {
  1160. "(my_service_option)": "FOO"
  1161. }
  1162. }]);
  1163. var builder = ProtoBuf.loadProtoFile(__dirname+"/custom-options.proto");
  1164. var root = builder.build(),
  1165. MyService = root.MyService,
  1166. RequestType = root.RequestType,
  1167. ResponseType = root.ResponseType,
  1168. called = false;
  1169. test.deepEqual(MyService.$options, {
  1170. "(my_service_option)": "FOO"
  1171. });
  1172. test.deepEqual(MyService.MyMethod.$options, {
  1173. "(my_method_option).foo": 567,
  1174. "(my_method_option).bar": "Some string"
  1175. });
  1176. // Provide the service with your actual RPC implementation based on whatever framework you like most.
  1177. var myService = new MyService(function(method, req, callback) {
  1178. test.strictEqual(method, ".MyService.MyMethod");
  1179. test.ok(req instanceof RequestType);
  1180. called = true;
  1181. // In this case we just return no error and our pre-built response. This must be properly async!
  1182. setTimeout(callback.bind(this, null, (new ResponseType()).encode() /* as raw bytes for debugging */ ));
  1183. });
  1184. test.deepEqual(myService.$options, MyService.$options);
  1185. test.deepEqual(myService.MyMethod.$options, MyService.MyMethod.$options);
  1186. // Call the service with your request message and provide a callback. This will call your actual service
  1187. // implementation to perform the request and gather a response before calling the callback. If the
  1188. // request or response type is invalid i.e. not an instance of RequestType or ResponseType, your
  1189. // implementation will not be called as ProtoBuf.js handles this case internally and directly hands the
  1190. // error to your callback below.
  1191. myService.MyMethod(new RequestType(), function(err, res) {
  1192. // We get: err = null, res = our prebuilt response. And that's it.
  1193. if (err !== null) {
  1194. fail(err);
  1195. }
  1196. test.strictEqual(called, true);
  1197. test.ok(res instanceof ResponseType);
  1198. test.done();
  1199. });
  1200. myService.MyMethod(new RequestType().encode(), function(err, res) {
  1201. // We get: err = null, res = our prebuilt response. And that's it.
  1202. if (err !== null) {
  1203. fail(err);
  1204. }
  1205. test.strictEqual(called, true);
  1206. test.ok(res instanceof ResponseType);
  1207. test.done();
  1208. });
  1209. } catch (e) {
  1210. fail(e);
  1211. }
  1212. },
  1213. // Properly ignore "syntax" and "extensions" keywords
  1214. // The corresponding .proto file has been removed upon request
  1215. /* "gtfs-realtime": function(test) {
  1216. try {
  1217. test.doesNotThrow(function() {
  1218. ProtoBuf.loadProtoFile(__dirname+"/gtfs-realtime.proto");
  1219. });
  1220. } catch (e) {
  1221. fail(e);
  1222. }
  1223. test.done();
  1224. }, */
  1225. "delimited": function(test) {
  1226. try {
  1227. var builder = ProtoBuf.loadProto("message Position { required int32 x = 1; required int32 y = 2; }");
  1228. var Position = builder.build("Position");
  1229. var bb = new ByteBuffer();
  1230. for (var i=0; i<2; i++) {
  1231. var position = new Position(10,10);
  1232. position.encodeDelimited(bb);
  1233. }
  1234. bb.flip();
  1235. for (i=0; i<2; i++) {
  1236. position = Position.decodeDelimited(bb);
  1237. test.strictEqual(position.x, 10);
  1238. test.strictEqual(position.y, 10);
  1239. }
  1240. } catch (e) {
  1241. fail(e);
  1242. }
  1243. test.done();
  1244. },
  1245. "stringify": function(test) {
  1246. try {
  1247. var builder = ProtoBuf.loadProto("message Position { required int32 x = 1; required int64 y = 2; }");
  1248. var Position = builder.build("Position");
  1249. var position = new Position(1, ProtoBuf.Long.fromNumber(2));
  1250. var json = JSON.stringify(position);
  1251. test.strictEqual(json, '{"x":1,"y":{"low":2,"high":0,"unsigned":false}}');
  1252. position = new Position(JSON.parse(json));
  1253. test.strictEqual(position.x, 1);
  1254. test.ok(position.y instanceof ProtoBuf.Long);
  1255. test.deepEqual(position.y, {"low":2,"high":0,"unsigned":false});
  1256. // Also test if this encodes and decodes properly
  1257. position = Position.decode(position.encode());
  1258. test.ok(position.y instanceof ProtoBuf.Long);
  1259. test.deepEqual(position.y, {"low": 2, "high": 0, "unsigned": false });
  1260. } catch (e) {
  1261. fail(e);
  1262. }
  1263. test.done();
  1264. },
  1265. "fields": function(test) {
  1266. try {
  1267. var builder = ProtoBuf.loadProtoFile(__dirname+"/optional.proto");
  1268. var Test1 = builder.build("Test1");
  1269. var test1 = new Test1();
  1270. test.strictEqual(test1.a, null);
  1271. test.deepEqual(Object.keys(test1), ['a','b']);
  1272. var bb = test1.encode();
  1273. test1 = Test1.decode(bb);
  1274. test.strictEqual(test1.a, null);
  1275. test.deepEqual(Object.keys(test1), ['a','b']);
  1276. } catch (e) {
  1277. fail(e);
  1278. }
  1279. test.done();
  1280. },
  1281. "fieldsToCamelCase": function(test) {
  1282. try {
  1283. ProtoBuf.convertFieldsToCamelCase = true;
  1284. var builder = ProtoBuf.loadProtoFile(__dirname+"/camelcase.proto");
  1285. var Test = builder.build("Test"),
  1286. TTest = builder.lookup("Test");
  1287. var msg = new Test();
  1288. // Reverted collision on 1st
  1289. test.strictEqual(msg.some_field, null);
  1290. test.strictEqual(msg.someField, null);
  1291. test.equal(TTest.getChild("some_field").id, 1);
  1292. test.equal(TTest.getChild("someField").id, 2);
  1293. // Reverted collision on 2nd
  1294. test.strictEqual(msg.aField, null);
  1295. test.strictEqual(msg.a_field, null);
  1296. test.equal(TTest.getChild("aField").id, 3);
  1297. test.equal(TTest.getChild("a_field").id, 4);
  1298. // No collision
  1299. test.strictEqual(msg.itsAField, null);
  1300. test.equal(TTest.getChild("itsAField").id, 5);
  1301. test.ok(typeof msg.set_its_a_field === "function");
  1302. test.ok(typeof msg.setItsAField === "function");
  1303. ProtoBuf.convertFieldsToCamelCase = false;
  1304. } catch (e) {
  1305. ProtoBuf.convertFieldsToCamelCase = false;
  1306. fail(e);
  1307. }
  1308. test.done();
  1309. },
  1310. "setarray": function(test) {
  1311. try {
  1312. var builder = ProtoBuf.loadProtoFile(__dirname+"/setarray.proto");
  1313. var root = builder.build(),
  1314. Outer = root.Outer,
  1315. Inner = root.Inner,
  1316. inners = [];
  1317. // Array of repeated messages
  1318. inners.push(new Inner("a"), new Inner("b"), new Inner("c"));
  1319. var outer = new Outer();
  1320. outer.setInners(inners);
  1321. test.deepEqual(outer.inners, inners);
  1322. // Array of repeated message objects
  1323. inners = [];
  1324. inners.push({ str: 'a' }, { str: 'b' }, { str: 'c' });
  1325. outer.setInners(inners); // Converts
  1326. test.ok(outer.inners[0] instanceof Inner);
  1327. test.deepEqual(outer.inners, inners);
  1328. } catch (e) {
  1329. fail(e);
  1330. }
  1331. test.done();
  1332. },
  1333. // Make sure that our example at https://github.com/dcodeIO/ProtoBuf.js/wiki is not nonsense
  1334. "pingexample": function(test) {
  1335. try {
  1336. var builder = ProtoBuf.loadProtoFile(__dirname+"/PingExample.proto");
  1337. var Message = builder.build("Message");
  1338. var msg = new Message();
  1339. msg.ping = new Message.Ping(123456789);
  1340. var bb = msg.encode();
  1341. test.strictEqual(bb.limit, 7);
  1342. msg = Message.decode(bb);
  1343. test.ok(msg.ping);
  1344. test.notOk(msg.pong);
  1345. test.strictEqual(msg.ping.time, 123456789);
  1346. } catch (e) {
  1347. fail(e);
  1348. }
  1349. test.done();
  1350. },
  1351. "negInt32": function(test) {
  1352. try {
  1353. var builder = ProtoBuf.loadProto("message Test { required int32 value = 2; }");
  1354. var Test = builder.build("Test");
  1355. var t = new Test(-1);
  1356. var size = t.calculate();
  1357. var bb = t.encode(); // flips
  1358. test.strictEqual(bb.remaining(), size);
  1359. test.strictEqual(bb.toBase64(), "EP///////////wE=");
  1360. t = Test.decode(bb);
  1361. test.strictEqual(t.value, -1);
  1362. } catch (e) {
  1363. fail(e);
  1364. }
  1365. test.done();
  1366. },
  1367. "negEnumId": function(test) {
  1368. try {
  1369. test.doesNotThrow(function() {
  1370. var builder = ProtoBuf.loadProtoFile(__dirname+"/negid.proto");
  1371. var Test = builder.build("Test");
  1372. test.strictEqual(Test.LobbyType.INVALID, -1);
  1373. var t = new Test(Test.LobbyType.INVALID);
  1374. test.strictEqual(t.type, -1);
  1375. var size = t.calculate();
  1376. var bb = t.encode(); // flips
  1377. test.strictEqual(bb.remaining(), size);
  1378. t = Test.decode(bb);
  1379. test.strictEqual(t.type, -1);
  1380. });
  1381. } catch (e) {
  1382. fail(e);
  1383. }
  1384. test.done();
  1385. },
  1386. "base64": function(test) {
  1387. try {
  1388. var Message = ProtoBuf.loadProto("message Message { required string s = 1; }").build("Message");
  1389. var msg = new Message("ProtoBuf.js");
  1390. var b64 = msg.toBase64();
  1391. test.strictEqual(b64, "CgtQcm90b0J1Zi5qcw==");
  1392. var msg2 = Message.decode64(b64);
  1393. test.deepEqual(msg, msg2);
  1394. msg2 = Message.decode(b64, "base64");
  1395. test.deepEqual(msg, msg2);
  1396. } catch (e) {
  1397. fail(e);
  1398. }
  1399. test.done();
  1400. },
  1401. "hex": function(test) {
  1402. try {
  1403. var Message = ProtoBuf.loadProto("message Message { required string s = 1; }").build("Message");
  1404. var msg = new Message("ProtoBuf.js");
  1405. var hex = msg.toHex();
  1406. test.strictEqual(hex, "0a0b50726f746f4275662e6a73");
  1407. var msg2 = Message.decodeHex(hex);
  1408. test.deepEqual(msg, msg2);
  1409. msg2 = Message.decode(hex, "hex");
  1410. test.deepEqual(msg, msg2);
  1411. } catch (e) {
  1412. fail(e);
  1413. }
  1414. test.done();
  1415. },
  1416. "forwardComp": function(test) {
  1417. try {
  1418. var Message = ProtoBuf.loadProto("message Message { required int32 a = 1; required string b = 2; required float c = 3; }").build("Message");
  1419. var msg = new Message(123, "abc", 0.123);
  1420. var bb = msg.encode();
  1421. Message = ProtoBuf.loadProto("message Message {}").build("Message");
  1422. test.doesNotThrow(function() {
  1423. Message.decode(bb);
  1424. });
  1425. test.strictEqual(bb.offset, bb.limit);
  1426. } catch (e) {
  1427. fail(e);
  1428. }
  1429. test.done();
  1430. },
  1431. "tokenizerLine": function(test) {
  1432. try {
  1433. var parser = new ProtoBuf.DotProto.Parser("package test;\n\nmessage Message {\n\trequired string invalid = 1;}ERROR\n"),
  1434. ast = null, err = null;
  1435. try {
  1436. ast = parser.parse();
  1437. } catch (caught) {
  1438. err = caught;
  1439. }
  1440. test.ok(err);
  1441. test.notOk(ast);
  1442. test.ok(err.message.indexOf("line 4:") >= 0);
  1443. } catch (e) {
  1444. fail(e);
  1445. }
  1446. test.done();
  1447. },
  1448. "excludeFields": function(test) {
  1449. try {
  1450. var builder = ProtoBuf.loadProto("message A { required int32 i = 1; } message B { required A A = 1; }");
  1451. builder.build();
  1452. } catch (e) {
  1453. fail(e);
  1454. }
  1455. test.done();
  1456. },
  1457. "proto2jsExtend": function(test) {
  1458. try {
  1459. var builder = ProtoBuf.loadJsonFile(__dirname+"/proto2js/Bar.json");
  1460. builder.build();
  1461. } catch (e) {
  1462. fail(e);
  1463. }
  1464. test.done();
  1465. },
  1466. "emptyMessage": function(test) {
  1467. try {
  1468. var builder = ProtoBuf.loadProto("message EmptyMessage {}"),
  1469. EmptyMessage = builder.build("EmptyMessage");
  1470. var msg = new EmptyMessage(),
  1471. ab = msg.toArrayBuffer();
  1472. test.strictEqual(ab.byteLength, 0);
  1473. } catch (e) {
  1474. fail(e);
  1475. }
  1476. test.done();
  1477. },
  1478. "toRaw": function(test) {
  1479. try {
  1480. var builder = ProtoBuf.loadProto("message MyMessage { required int32 a = 1; required int32 b = 2; required bytes c = 3; }"),
  1481. MyMessage = builder.build("MyMessage");
  1482. var raw = { a: 1, b: 2, c: "YWJj" },
  1483. myMessage = new MyMessage(raw);
  1484. test.deepEqual(myMessage.c.toBase64(), raw.c);
  1485. test.deepEqual(myMessage.toRaw(true), raw);
  1486. } catch (e) {
  1487. fail(e);
  1488. }
  1489. test.done();
  1490. },
  1491. "singleQuotedString": function(test) {
  1492. try{
  1493. var builder = ProtoBuf.loadProtoFile(__dirname+"/string_single_quote.proto");
  1494. var TestSingleQuoteString = builder.build("TestSingleQuoteString");
  1495. test.ok(typeof TestSingleQuoteString == 'function');
  1496. } catch (e) {
  1497. fail(e);
  1498. }
  1499. test.done();
  1500. },
  1501. "importDuplicateSingleQuote": function(test) {
  1502. try {
  1503. var builder = ProtoBuf.loadProtoFile(__dirname+"/import_a_single_quote.proto");
  1504. test.doesNotThrow(function() {
  1505. ProtoBuf.loadProtoFile(__dirname+"/import_b.proto", builder);
  1506. });
  1507. var root = builder.build();
  1508. test.ok(root.A);
  1509. test.ok(root.B);
  1510. test.ok(root.Common);
  1511. } catch (e) {
  1512. fail(e);
  1513. }
  1514. test.done();
  1515. },
  1516. "importStringSuccessively": function(test) {
  1517. try {
  1518. var proto1 = "message A { required string a = 1; };";
  1519. var proto2 = "import \"proto1.proto\"; message B { required A a = 1; };";
  1520. var builder = ProtoBuf.loadProto(proto1, "proto1.proto");
  1521. ProtoBuf.loadProto(proto2, builder, "proto2.proto");
  1522. var root = builder.build();
  1523. test.ok(root.A);
  1524. test.ok(root.B);
  1525. } catch (e) {
  1526. fail(e);
  1527. }
  1528. test.done();
  1529. },
  1530. "multilineString": function(test) {
  1531. try {
  1532. var proto = "message TestMessage { required string test = 1 [default = \"1\" \"2\"\n\"3\"];}";
  1533. var builder = ProtoBuf.loadProto(proto, "multilineString.proto");
  1534. var TestMessage = builder.build("TestMessage"),
  1535. testMessage = new TestMessage();
  1536. test.strictEqual(testMessage.test, "123");
  1537. test.done();
  1538. } catch (e) {
  1539. fail(e);
  1540. }
  1541. test.done();
  1542. },
  1543. "packable": function(test) {
  1544. try {
  1545. var proto = 'message Inner { required int32 id=2; }\nmessage Outer { repeated Inner inner = 1 [packed=true]; }';
  1546. var builder = ProtoBuf.loadProto(proto);
  1547. var root = builder.build();
  1548. var inner = new root.Inner(1),
  1549. outer = new root.Outer(inner);
  1550. var bb = outer.encode().compact();
  1551. test.strictEqual(bb.toDebug(), "<0A 02 10 01>");
  1552. // 0A: wt 2, id 1
  1553. // 02: len 2
  1554. // 10: wt 0, id 2
  1555. // 01: 1
  1556. var outer2 = root.Outer.decode(bb);
  1557. test.strictEqual(outer2.inner.id, 1);
  1558. } catch (e) {
  1559. fail(e);
  1560. }
  1561. test.done();
  1562. },
  1563. "$type": function(test) {
  1564. var builder = ProtoBuf.loadProto("message Test {}");
  1565. var Test = builder.build("Test"),
  1566. TTest = builder.lookup("Test");
  1567. test.strictEqual(new Test().$type, TTest);
  1568. test.done();
  1569. },
  1570. "descriptor": function(test) {
  1571. try {
  1572. var proto = 'import "./google/protobuf/descriptor.proto";';
  1573. var builder = ProtoBuf.loadProto(proto, "tests/proto.proto");
  1574. var root = builder.build("google.protobuf");
  1575. test.ok(root.FileDescriptorSet);
  1576. } catch (e) {
  1577. fail(e);
  1578. }
  1579. test.done();
  1580. },
  1581. "mismatchedNesting": function(test) {
  1582. try {
  1583. var proto = "message Child { optional uint32 foo = 1; } message FakeChild { optional uint32 foo = 1; } message Parent { optional Child child = 1; }";
  1584. var builder = ProtoBuf.loadProto(proto, "tests/mismatchedNesting.proto");
  1585. var root = builder.build();
  1586. var foo = new root.Parent({ child: new root.FakeChild({ foo: 1 })});
  1587. } catch (e) {
  1588. fail(e);
  1589. }
  1590. test.done();
  1591. },
  1592. /* "mismatchedType": function(test) {
  1593. try {
  1594. var proto = "message Test1 { optional string foo = 1; }";
  1595. proto += "message Test2 { optional int32 foo = 1; }";
  1596. var builder = ProtoBuf.loadProto(proto, "tests/mistmatchedType.proto");
  1597. var root = builder.build();
  1598. var test1 = new root.Test1({ foo: 'bar' });
  1599. var test2 = root.Test2.decode(test1.encode());
  1600. } catch (e) {
  1601. fail(e);
  1602. }
  1603. test.done();
  1604. }, */
  1605. "builderOptions": function(test) {
  1606. try {
  1607. var proto = "message Foo { optional uint32 foo_bar = 1; }";
  1608. var builder = ProtoBuf.newBuilder({
  1609. convertFieldsToCamelCase: true
  1610. });
  1611. ProtoBuf.loadProto(proto, builder, "tests/builderOptions.proto");
  1612. var Foo = builder.build("Foo");
  1613. test.strictEqual(ProtoBuf.convertFieldsToCamelCase, false);
  1614. test.strictEqual(builder.options.convertFieldsToCamelCase, true);
  1615. var foo = new Foo();
  1616. test.ok(typeof foo.fooBar !== 'undefined');
  1617. test.ok(typeof foo.foo_bar === 'undefined');
  1618. test.done();
  1619. } catch (e) {
  1620. fail(e);
  1621. }
  1622. test.done();
  1623. },
  1624. "proto3": function(test) {
  1625. try {
  1626. var builder = ProtoBuf.loadProtoFile(__dirname+"/proto3.proto");
  1627. test.doesNotThrow(function() {
  1628. ProtoBuf.loadProtoFile(__dirname+"/proto3.proto", builder);
  1629. });
  1630. var root = builder.build();
  1631. test.ok(root.test.Foo.$type.syntax === 'proto3');
  1632. } catch (e) {
  1633. fail(e);
  1634. }
  1635. test.done();
  1636. },
  1637. // FIXME: This test relied on some bloated builder functionality that has been removed.
  1638. // Is it even mandatory to strictly disallow proto2/3 mixing, even if that would be illegal in the official
  1639. // implementation?
  1640. /* "proto3DisallowedFeatures": function(test) {
  1641. try {
  1642. // Required field
  1643. var proto = "syntax = \"proto3\"; message Foo { required int32 field = 1; }";
  1644. var builder = ProtoBuf.newBuilder();
  1645. ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
  1646. test.ok(false); // ^ should throw
  1647. } catch (e) {
  1648. test.ok(/^Not a valid definition/.test(e.message));
  1649. }
  1650. try {
  1651. // Field with default value
  1652. var proto = "syntax = \"proto3\"; message Foo { int32 field = 1 [default=42]; }";
  1653. var builder = ProtoBuf.newBuilder();
  1654. ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
  1655. test.ok(false); // ^ should throw
  1656. } catch (e) {
  1657. test.ok(/^Not a valid definition/.test(e.message));
  1658. }
  1659. try {
  1660. // Message with extension range
  1661. var proto = "syntax = \"proto3\"; message Foo { extensions 100 to max; } ";
  1662. var builder = ProtoBuf.newBuilder();
  1663. ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
  1664. test.ok(false); // ^ should throw
  1665. } catch (e) {
  1666. test.ok(/^Not a valid definition/.test(e.message));
  1667. }
  1668. try {
  1669. // Message with extension
  1670. var proto = "syntax = \"proto3\"; message Foo { extensions 100 to max; } " +
  1671. "message Bar { extend Foo { optional Bar bar = 100; } }";
  1672. var builder = ProtoBuf.newBuilder();
  1673. ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
  1674. test.ok(false); // ^ should throw
  1675. } catch (e) {
  1676. test.ok(/^Not a valid definition/.test(e.message));
  1677. }
  1678. try {
  1679. // Enum with non-zero first entry.
  1680. var proto = "syntax = \"proto3\"; enum E { A = 1; B = 2; }";
  1681. var builder = ProtoBuf.newBuilder();
  1682. ProtoBuf.loadProto(proto, builder, "tests/proto3DisallowedFeatures.proto");
  1683. test.ok(false); // ^ should throw
  1684. } catch (e) {
  1685. test.ok(/^Not a valid definition/.test(e.message));
  1686. }
  1687. try {
  1688. // Proto3 message referring to proto2 enum.
  1689. var proto2 = "syntax = \"proto2\"; enum E { A = 1; B = 2; }";
  1690. var proto3 = "syntax = \"proto3\"; message Test { E enum_field = 1; }";
  1691. var builder = ProtoBuf.newBuilder();
  1692. ProtoBuf.loadProto(proto2, builder, "tests/proto3DisallowedFeatures1.proto");
  1693. ProtoBuf.loadProto(proto3, builder, "tests/proto3DisallowedFeatures3.proto");
  1694. test.ok(false); // ^ should throw
  1695. } catch (e) {
  1696. test.ok(/^Proto3 message refers to proto2 enum/.test(e.message));
  1697. }
  1698. test.done();
  1699. }, */
  1700. "proto3FieldPresence": function(test) {
  1701. var proto =
  1702. "syntax = \"proto3\";\n" +
  1703. "message Test {\n" +
  1704. " int32 field_int32 = 1;\n" +
  1705. " int64 field_int64 = 2;\n" +
  1706. " string field_str = 3;\n" +
  1707. " bytes field_bytes = 4;\n" +
  1708. " Test field_msg = 5;\n" +
  1709. " Enum field_enum = 6;\n" +
  1710. " repeated int32 rpt_int32 = 11;\n" +
  1711. " repeated int64 rpt_int64 = 12;\n" +
  1712. " repeated string rpt_str = 13;\n" +
  1713. " repeated bytes rpt_bytes = 14;\n" +
  1714. " repeated Test rpt_msg = 15;\n" +
  1715. " repeated Enum rpt_enum = 16;\n" +
  1716. " oneof oneof_type { bool oneof_bool = 17; };\n" +
  1717. "}\n" +
  1718. "enum Enum { Default = 0; A = 1; B = 2; }\n";
  1719. var builder = ProtoBuf.newBuilder();
  1720. ProtoBuf.loadProto(proto, builder, "test/proto3FieldPresence.proto");
  1721. var Test = builder.build('Test'),
  1722. Enum = builder.build('Enum');
  1723. var testMsg = new Test();
  1724. test.strictEqual(testMsg.field_int32, 0);
  1725. test.strictEqual(testMsg.field_int64.low, 0);
  1726. test.strictEqual(testMsg.field_int64.high, 0);
  1727. test.strictEqual(testMsg.field_str, "");
  1728. test.strictEqual(testMsg.field_msg, null);
  1729. test.ok(testMsg.field_bytes instanceof ByteBuffer);
  1730. test.strictEqual(testMsg.field_bytes.remaining(), 0);
  1731. test.strictEqual(testMsg.rpt_int32.length, 0);
  1732. test.strictEqual(testMsg.oneof_type, null);
  1733. test.strictEqual(testMsg.oneof_bool, false);
  1734. // No fields should go on the wire, even though they're set
  1735. var encoded = testMsg.encode();
  1736. test.strictEqual(encoded.remaining(), 0);
  1737. testMsg.field_int32 = 42;
  1738. encoded = testMsg.encode();
  1739. test.strictEqual(encoded.remaining(), 2);
  1740. testMsg.field_int32 = 0;
  1741. encoded = testMsg.encode();
  1742. test.strictEqual(encoded.remaining(), 0);
  1743. // Enum fields should be able to carry arbitrary values.
  1744. testMsg.field_enum = 42;
  1745. test.strictEqual(testMsg.field_enum, 42);
  1746. encoded = testMsg.encode();
  1747. testMsg = Test.decode(encoded);
  1748. test.strictEqual(testMsg.field_enum, 42);
  1749. // Explicitly set fields that are part of an oneof should
  1750. // be encoded even if set to their default value
  1751. testMsg = new Test();
  1752. testMsg.set("oneof_bool", false);
  1753. test.strictEqual(testMsg.oneof_type, "oneof_bool");
  1754. encoded = testMsg.encode().compact();
  1755. test.strictEqual(encoded.toString("debug"), "<88 01 00>"); // 17|varint (0term) + varint 0
  1756. var decoded = Test.decode(encoded);
  1757. test.strictEqual(decoded.oneof_type, "oneof_bool");
  1758. test.strictEqual(decoded.oneof_bool, false);
  1759. test.done();
  1760. },
  1761. "mapContainer": function(test) {
  1762. var proto =
  1763. "message Test {\n" +
  1764. " map<string, int32> map_string_int32 = 1;\n" +
  1765. " map<string, int64> map_string_int64 = 2;\n" +
  1766. " map<string, string> map_string_string = 3;\n" +
  1767. " map<string, Test> map_string_msg = 4;\n" +
  1768. " map<string, Enum> map_string_enum = 5;\n" +
  1769. " map<int32, string> map_int32_string = 6;\n" +
  1770. " map<int64, string> map_int64_string = 7;\n" +
  1771. " map<bool, string> map_bool_string = 9;\n" +
  1772. "}\n" +
  1773. "enum Enum { Default = 0; A = 1; B = 2; }\n";
  1774. var builder = ProtoBuf.newBuilder();
  1775. ProtoBuf.loadProto(proto, builder, "test/mapContainer.proto");
  1776. var map_string_int32 =
  1777. new ProtoBuf.Map(builder.lookup("Test.map_string_int32"));
  1778. test.strictEqual(map_string_int32.size, 0);
  1779. test.strictEqual(map_string_int32.has("asdf"), false);
  1780. test.strictEqual(map_string_int32.get("asdf"), undefined);
  1781. map_string_int32.set("asdf", 42);
  1782. test.strictEqual(map_string_int32.has("asdf"), true);
  1783. test.strictEqual(map_string_int32.get("asdf"), 42);
  1784. var it = map_string_int32.keys();
  1785. var itVal = it.next();
  1786. test.strictEqual(itVal.done, false);
  1787. test.strictEqual(itVal.value, "asdf");
  1788. itVal = it.next();
  1789. test.strictEqual(itVal.done, true);
  1790. it = map_string_int32.values();
  1791. itVal = it.next();
  1792. test.strictEqual(itVal.done, false);
  1793. test.strictEqual(itVal.value, 42);
  1794. itVal = it.next();
  1795. test.strictEqual(itVal.done, true);
  1796. it = map_string_int32.entries();
  1797. itVal = it.next();
  1798. test.strictEqual(itVal.done, false);
  1799. test.deepEqual(itVal.value, ["asdf", 42]);
  1800. itVal = it.next();
  1801. test.strictEqual(itVal.done, true);
  1802. map_string_int32.set("jkl;", 84);
  1803. test.strictEqual(map_string_int32.has("jkl;"), true);
  1804. test.strictEqual(map_string_int32.has("asdf"), true);
  1805. test.strictEqual(map_string_int32.size, 2);
  1806. map_string_int32.delete("jkl;");
  1807. test.strictEqual(map_string_int32.has("jkl;"), false);
  1808. test.strictEqual(map_string_int32.get("jkl;"), undefined);
  1809. test.strictEqual(map_string_int32.size, 1);
  1810. map_string_int32.clear();
  1811. test.strictEqual(map_string_int32.size, 0);
  1812. try {
  1813. map_string_int32.set("asdf", 42.1);
  1814. test.ok(false); // ^ should throw
  1815. } catch(e) {
  1816. test.ok(e.message.match(/not an integer/));
  1817. }
  1818. try {
  1819. map_string_int32.set(42, 42);
  1820. test.ok(false); // ^ should throw
  1821. } catch(e) {
  1822. test.ok(e.message.match(/not a string/));
  1823. }
  1824. // Test various key types to ensure that value->string->value
  1825. // conversion works.
  1826. var map_int32_string =
  1827. new ProtoBuf.Map(builder.lookup("Test.map_int32_string"));
  1828. test.strictEqual(map_int32_string.size, 0);
  1829. map_int32_string.set(12345678, "asdf");
  1830. test.strictEqual(map_int32_string.size, 1);
  1831. test.strictEqual(map_int32_string.has(12345678), true);
  1832. test.strictEqual(map_int32_string.get(12345678), "asdf");
  1833. var map_int64_string =
  1834. new ProtoBuf.Map(builder.lookup("Test.map_int64_string"));
  1835. test.strictEqual(map_int64_string.size, 0);
  1836. map_int64_string.set("9223372036854775807", "asdf");
  1837. test.strictEqual(map_int64_string.size, 1);
  1838. test.strictEqual(map_int64_string.has("9223372036854775807"), true);
  1839. test.strictEqual(map_int64_string.get("9223372036854775807"), "asdf");
  1840. // Ensure that initialization from a raw object works.
  1841. var map_int32_string =
  1842. new ProtoBuf.Map(builder.lookup("Test.map_int32_string"),
  1843. { 42: "asdf" });
  1844. test.strictEqual(map_int32_string.size, 1);
  1845. test.strictEqual(map_int32_string.keys().next().value, 42);
  1846. var map_int64_string =
  1847. new ProtoBuf.Map(builder.lookup("Test.map_int64_string"),
  1848. { "9223372036854775807": "asdf" });
  1849. test.strictEqual(map_int64_string.size, 1);
  1850. var i64 = map_int64_string.keys().next().value;
  1851. test.ok(i64 instanceof ProtoBuf.Long);
  1852. test.strictEqual(i64.toString(), "9223372036854775807");
  1853. test.done();
  1854. },
  1855. "mapField": function(test) {
  1856. var proto =
  1857. "message Test {\n" +
  1858. " map<string, int32> map_string_int32 = 1;\n" +
  1859. " map<string, int64> map_string_int64 = 2;\n" +
  1860. " map<string, string> map_string_string = 3;\n" +
  1861. " map<string, Test> map_string_msg = 4;\n" +
  1862. " map<string, Enum> map_string_enum = 5;\n" +
  1863. " map<int32, string> map_int32_string = 6;\n" +
  1864. " map<int64, string> map_int64_string = 7;\n" +
  1865. " map<bool, string> map_bool_string = 9;\n" +
  1866. "}\n" +
  1867. "enum Enum { Default = 0; A = 1; B = 2; }\n";
  1868. var builder = ProtoBuf.newBuilder();
  1869. ProtoBuf.loadProto(proto, builder, "test/mapField.proto");
  1870. var Test = builder.build('Test'),
  1871. Enum = builder.build('Enum');
  1872. var testMsg = new Test();
  1873. test.strictEqual(testMsg.map_string_int32.size, 0);
  1874. test.strictEqual(testMsg.map_string_int64.size, 0);
  1875. test.strictEqual(testMsg.map_string_string.size, 0);
  1876. test.strictEqual(testMsg.map_string_msg.size, 0);
  1877. test.strictEqual(testMsg.map_string_enum.size, 0);
  1878. test.strictEqual(testMsg.map_int32_string.size, 0);
  1879. test.strictEqual(testMsg.map_int64_string.size, 0);
  1880. test.strictEqual(testMsg.map_bool_string.size, 0);
  1881. testMsg.$set('map_string_int32', { 'asdf': 42 });
  1882. try {
  1883. testMsg.$set('map_string_int32', { 'asdf': 42.1 });
  1884. test.ok(false); // ^ should throw
  1885. } catch (e) {
  1886. test.ok(e.message.match(/Illegal/));
  1887. }
  1888. test.done();
  1889. },
  1890. "mapEncodeDecode": function(test) {
  1891. var proto =
  1892. "message Test {\n" +
  1893. " map<string, int32> map_string_int32 = 1;\n" +
  1894. " map<string, int64> map_string_int64 = 2;\n" +
  1895. " map<string, string> map_string_string = 3;\n" +
  1896. " map<string, Test> map_string_msg = 4;\n" +
  1897. " map<string, Enum> map_string_enum = 5;\n" +
  1898. " map<int32, string> map_int32_string = 6;\n" +
  1899. " map<int64, string> map_int64_string = 7;\n" +
  1900. " map<bool, string> map_bool_string = 9;\n" +
  1901. "}\n" +
  1902. "enum Enum { Default = 0; A = 1; B = 2; }\n";
  1903. var builder = ProtoBuf.newBuilder();
  1904. ProtoBuf.loadProto(proto, builder, "test/mapField.proto");
  1905. var Test = builder.build('Test'),
  1906. Enum = builder.build('Enum');
  1907. var testMsg = new Test();
  1908. testMsg.map_string_int32.set("a", 1);
  1909. testMsg.map_string_int32.set("b", 2);
  1910. testMsg.map_string_int64.set("c", "12345678901234");
  1911. testMsg.map_string_int64.set("d", "98765432109876");
  1912. testMsg.map_string_string.set("e", "asdf");
  1913. testMsg.map_string_string.set("f", "jkl;");
  1914. testMsg.map_string_enum.set("g", Enum.A);
  1915. testMsg.map_string_enum.set("h", Enum.B);
  1916. testMsg.map_int32_string.set(9, "a");
  1917. testMsg.map_int32_string.set(10, "b");
  1918. testMsg.map_int64_string.set("12345678901234", "a");
  1919. testMsg.map_int64_string.set("98765432109876", "b");
  1920. testMsg.map_bool_string.set(false, "a");
  1921. testMsg.map_bool_string.set(true, "b");
  1922. var encoded = testMsg.encode();
  1923. testMsg = Test.decode(encoded);
  1924. test.strictEqual(testMsg.map_string_int32.get("a"), 1);
  1925. test.strictEqual(testMsg.map_string_int32.get("b"), 2);
  1926. test.strictEqual(testMsg.map_string_int64.get("c").toString(), "12345678901234");
  1927. test.strictEqual(testMsg.map_string_int64.get("d").toString(), "98765432109876");
  1928. test.strictEqual(testMsg.map_string_string.get("e"), "asdf");
  1929. test.strictEqual(testMsg.map_string_string.get("f"), "jkl;");
  1930. test.strictEqual(testMsg.map_string_enum.get("g"), Enum.A);
  1931. test.strictEqual(testMsg.map_string_enum.get("h"), Enum.B);
  1932. test.strictEqual(testMsg.map_int32_string.get(9), "a");
  1933. test.strictEqual(testMsg.map_int32_string.get(10), "b");
  1934. test.strictEqual(testMsg.map_int64_string.get("12345678901234"), "a");
  1935. test.strictEqual(testMsg.map_int64_string.get("98765432109876"), "b");
  1936. test.strictEqual(testMsg.map_bool_string.get(false), "a");
  1937. test.strictEqual(testMsg.map_bool_string.get(true), "b");
  1938. test.done();
  1939. },
  1940. "proto3Json": function(test) {
  1941. var proto =
  1942. "syntax = \"proto3\";\n" +
  1943. "message Test {\n" +
  1944. " int32 optional_int32 = 1;\n" +
  1945. " int64 optional_int64 = 2;\n" +
  1946. " string optional_string = 3;\n" +
  1947. " bytes optional_bytes = 4;\n" +
  1948. " bool optional_bool = 5;\n" +
  1949. " Enum optional_enum = 6;\n" +
  1950. " repeated int32 repeated_int32 = 11;\n" +
  1951. " repeated int64 repeated_int64 = 12;\n" +
  1952. " repeated string repeated_string = 13;\n" +
  1953. " repeated bytes repeated_bytes = 14;\n" +
  1954. " repeated bool repeated_bool = 15;\n" +
  1955. " repeated Enum repeated_enum = 16;\n" +
  1956. " map<string, int32> map_string_int32 = 20;\n" +
  1957. " map<string, int64> map_string_int64 = 21;\n" +
  1958. " map<string, string> map_string_string = 22;\n" +
  1959. " map<string, Enum> map_string_enum = 24;\n" +
  1960. " map<int32, string> map_int32_string = 25;\n" +
  1961. " map<int64, string> map_int64_string = 26;\n" +
  1962. " map<bool, string> map_bool_string = 27;\n" +
  1963. "}\n" +
  1964. "enum Enum { Default = 0; A = 1; B = 2; }\n";
  1965. var builder = ProtoBuf.newBuilder();
  1966. ProtoBuf.loadProto(proto, builder, "test/mapField.proto");
  1967. var Test = builder.build('Test'),
  1968. Enum = builder.build('Enum');
  1969. var testMsg = new Test();
  1970. testMsg.optional_int32 = 1;
  1971. testMsg.optional_int64 = "12345678901234";
  1972. testMsg.optional_string = "hello";
  1973. testMsg.optional_bytes = ProtoBuf.ByteBuffer.fromBinary("\x00\xFF\x80");
  1974. testMsg.optional_bool = true;
  1975. testMsg.optional_enum = Enum.A;
  1976. testMsg.repeated_int32.push(1);
  1977. testMsg.repeated_int64.push("12345678901234");
  1978. testMsg.repeated_string.push("hello");
  1979. testMsg.repeated_bytes.push(ProtoBuf.ByteBuffer.fromBinary("\x00\xFF\x80"));
  1980. testMsg.repeated_bool.push(true);
  1981. testMsg.repeated_enum.push(Enum.A);
  1982. testMsg.map_string_int32.set("a", 1);
  1983. testMsg.map_string_int32.set("b", 2);
  1984. testMsg.map_string_int64.set("c", "12345678901234");
  1985. testMsg.map_string_int64.set("d", "98765432109876");
  1986. testMsg.map_string_string.set("e", "asdf");
  1987. testMsg.map_string_string.set("f", "jkl;");
  1988. testMsg.map_string_enum.set("g", Enum.A);
  1989. testMsg.map_string_enum.set("h", Enum.B);
  1990. testMsg.map_int32_string.set(9, "a");
  1991. testMsg.map_int32_string.set(10, "b");
  1992. testMsg.map_int64_string.set("12345678901234", "a");
  1993. testMsg.map_int64_string.set("98765432109876", "b");
  1994. testMsg.map_bool_string.set(false, "a");
  1995. testMsg.map_bool_string.set(true, "b");
  1996. var jsonObj = JSON.parse(testMsg.encodeJSON());
  1997. test.deepEqual(jsonObj,
  1998. {
  1999. optional_int32: 1,
  2000. optional_int64: "12345678901234",
  2001. optional_string: "hello",
  2002. optional_bytes: "AP+A", // base64
  2003. optional_bool: true,
  2004. optional_enum: "A",
  2005. repeated_int32: [1],
  2006. repeated_int64: ["12345678901234"],
  2007. repeated_string: ["hello"],
  2008. repeated_bytes: ["AP+A"], // base64
  2009. repeated_bool: [true],
  2010. repeated_enum: ["A"],
  2011. map_string_int32: { "a": 1, "b": 2 },
  2012. map_string_int64: { "c": "12345678901234", "d": "98765432109876" },
  2013. map_string_string: { "e": "asdf", "f": "jkl;" },
  2014. map_string_enum: { "g": "A", "h": "B" },
  2015. map_int32_string: { "9": "a", "10": "b" },
  2016. map_int64_string: { "12345678901234": "a", "98765432109876": "b" },
  2017. map_bool_string: { "false": "a", "true": "b" },
  2018. });
  2019. var testMsg2 = Test.decodeJSON(testMsg.encodeJSON());
  2020. test.strictEqual(testMsg2.encodeJSON(), testMsg.encodeJSON());
  2021. test.done();
  2022. },
  2023. // Node.js only
  2024. "loaders": BROWSER ? {} : {
  2025. "commonjs": function(test) {
  2026. var fs = require("fs")
  2027. , vm = require("vm")
  2028. , util = require('util');
  2029. var code = fs.readFileSync(__dirname+"/../dist/"+FILE);
  2030. var exports = {};
  2031. var sandbox = new Sandbox({
  2032. module: {
  2033. exports: exports,
  2034. id: "protobufjs"
  2035. },
  2036. exports: exports,
  2037. require: (function() {
  2038. function require(mod) {
  2039. if (mod == 'bytebuffer') require.called = true;
  2040. return ByteBuffer;
  2041. }
  2042. require.called = false;
  2043. return require;
  2044. })()
  2045. });
  2046. vm.runInNewContext(code, sandbox, "ProtoBuf.js in CommonJS-VM");
  2047. // console.log(util.inspect(sandbox));
  2048. test.ok(typeof sandbox.module.exports == 'object');
  2049. test.ok(typeof sandbox.require != 'undefined' && sandbox.require.called);
  2050. test.done();
  2051. },
  2052. "amd": function(test) {
  2053. var fs = require("fs")
  2054. , vm = require("vm")
  2055. , util = require('util');
  2056. var code = fs.readFileSync(__dirname+"/../dist/"+FILE);
  2057. var sandbox = new Sandbox({
  2058. define: (function() {
  2059. function define() {
  2060. define.called = true;
  2061. }
  2062. define.amd = true;
  2063. define.called = false;
  2064. return define;
  2065. })()
  2066. });
  2067. vm.runInNewContext(code, sandbox, "ProtoBuf.js in AMD-VM");
  2068. // console.log(util.inspect(sandbox));
  2069. test.ok(sandbox.define.called == true);
  2070. test.done();
  2071. },
  2072. "shim": function(test) {
  2073. var fs = require("fs")
  2074. , vm = require("vm")
  2075. , util = require('util');
  2076. var code = fs.readFileSync(__dirname+"/../dist/"+FILE);
  2077. var sandbox = new Sandbox({
  2078. dcodeIO: {
  2079. ByteBuffer: ByteBuffer
  2080. }
  2081. });
  2082. vm.runInNewContext(code, sandbox, "ProtoBuf.js in shim-VM");
  2083. // console.log(util.inspect(sandbox));
  2084. test.ok(typeof sandbox.dcodeIO != 'undefined' && typeof sandbox.dcodeIO.ProtoBuf != 'undefined');
  2085. test.done();
  2086. }
  2087. }
  2088. };
  2089. if (typeof module != 'undefined' && module.exports) {
  2090. module.exports = suite;
  2091. } else {
  2092. global["suite"] = suite;
  2093. }
  2094. })(this);