idlharness.js 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837
  1. /*
  2. Distributed under both the W3C Test Suite License [1] and the W3C
  3. 3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
  4. policies and contribution forms [3].
  5. [1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
  6. [2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
  7. [3] http://www.w3.org/2004/10/27-testcases
  8. */
  9. /*
  10. * This file automatically generates browser tests for WebIDL interfaces, using
  11. * the testharness.js framework. To use, first include the following:
  12. *
  13. * <script src=/resources/testharness.js></script>
  14. * <script src=/resources/testharnessreport.js></script>
  15. * <script src=/resources/webidl2.js></script>
  16. * <script src=/resources/idlharness.js></script>
  17. *
  18. * Then you'll need some type of IDLs. Here's some script that can be run on a
  19. * spec written in HTML, which will grab all the elements with class="idl",
  20. * concatenate them, and replace the body so you can copy-paste:
  21. *
  22. var s = "";
  23. [].forEach.call(document.getElementsByClassName("idl"), function(idl) {
  24. //https://www.w3.org/Bugs/Public/show_bug.cgi?id=14914
  25. if (!idl.classList.contains("extract"))
  26. {
  27. s += idl.textContent + "\n\n";
  28. }
  29. });
  30. document.body.innerHTML = '<pre></pre>';
  31. document.body.firstChild.textContent = s;
  32. *
  33. * (TODO: write this in Python or something so that it can be done from the
  34. * command line instead.)
  35. *
  36. * Once you have that, put it in your script somehow. The easiest way is to
  37. * embed it literally in an HTML file with <script type=text/plain> or similar,
  38. * so that you don't have to do any escaping. Another possibility is to put it
  39. * in a separate .idl file that's fetched via XHR or similar. Sample usage:
  40. *
  41. * var idl_array = new IdlArray();
  42. * idl_array.add_untested_idls("interface Node { readonly attribute DOMString nodeName; };");
  43. * idl_array.add_idls("interface Document : Node { readonly attribute DOMString URL; };");
  44. * idl_array.add_objects({Document: ["document"]});
  45. * idl_array.test();
  46. *
  47. * This tests that window.Document exists and meets all the requirements of
  48. * WebIDL. It also tests that window.document (the result of evaluating the
  49. * string "document") has URL and nodeName properties that behave as they
  50. * should, and otherwise meets WebIDL's requirements for an object whose
  51. * primary interface is Document. It does not test that window.Node exists,
  52. * which is what you want if the Node interface is already tested in some other
  53. * specification's suite and your specification only extends or refers to it.
  54. * Of course, each IDL string can define many different things, and calls to
  55. * add_objects() can register many different objects for different interfaces:
  56. * this is a very simple example.
  57. *
  58. * TODO: Write assert_writable, assert_enumerable, assert_configurable and
  59. * their inverses, and use those instead of just checking
  60. * getOwnPropertyDescriptor.
  61. *
  62. * == Public methods of IdlArray ==
  63. *
  64. * IdlArray objects can be obtained with new IdlArray(). Anything not
  65. * documented in this section should be considered an implementation detail,
  66. * and outside callers should not use it.
  67. *
  68. * add_idls(idl_string):
  69. * Parses idl_string (throwing on parse error) and adds the results to the
  70. * IdlArray. All the definitions will be tested when you run test(). If
  71. * some of the definitions refer to other definitions, those must be present
  72. * too. For instance, if idl_string says that Document inherits from Node,
  73. * the Node interface must also have been provided in some call to add_idls()
  74. * or add_untested_idls().
  75. *
  76. * add_untested_idls(idl_string):
  77. * Like add_idls(), but the definitions will not be tested. If an untested
  78. * interface is added and then extended with a tested partial interface, the
  79. * members of the partial interface will still be tested. Also, all the
  80. * members will still be tested for objects added with add_objects(), because
  81. * you probably want to test that (for instance) window.document has all the
  82. * properties from Node, not just Document, even if the Node interface itself
  83. * is tested in a different test suite.
  84. *
  85. * add_objects(dict):
  86. * dict should be an object whose keys are the names of interfaces or
  87. * exceptions, and whose values are arrays of strings. When an interface or
  88. * exception is tested, every string registered for it with add_objects()
  89. * will be evaluated, and tests will be run on the result to verify that it
  90. * correctly implements that interface or exception. This is the only way to
  91. * test anything about [NoInterfaceObject] interfaces, and there are many
  92. * tests that can't be run on any interface without an object to fiddle with.
  93. *
  94. * The interface has to be the *primary* interface of all the objects
  95. * provided. For example, don't pass {Node: ["document"]}, but rather
  96. * {Document: ["document"]}. Assuming the Document interface was declared to
  97. * inherit from Node, this will automatically test that document implements
  98. * the Node interface too.
  99. *
  100. * Warning: methods will be called on any provided objects, in a manner that
  101. * WebIDL requires be safe. For instance, if a method has mandatory
  102. * arguments, the test suite will try calling it with too few arguments to
  103. * see if it throws an exception. If an implementation incorrectly runs the
  104. * function instead of throwing, this might have side effects, possibly even
  105. * preventing the test suite from running correctly.
  106. *
  107. * prevent_multiple_testing(name):
  108. * This is a niche method for use in case you're testing many objects that
  109. * implement the same interfaces, and don't want to retest the same
  110. * interfaces every single time. For instance, HTML defines many interfaces
  111. * that all inherit from HTMLElement, so the HTML test suite has something
  112. * like
  113. * .add_objects({
  114. * HTMLHtmlElement: ['document.documentElement'],
  115. * HTMLHeadElement: ['document.head'],
  116. * HTMLBodyElement: ['document.body'],
  117. * ...
  118. * })
  119. * and so on for dozens of element types. This would mean that it would
  120. * retest that each and every one of those elements implements HTMLElement,
  121. * Element, and Node, which would be thousands of basically redundant tests.
  122. * The test suite therefore calls prevent_multiple_testing("HTMLElement").
  123. * This means that once one object has been tested to implement HTMLElement
  124. * and its ancestors, no other object will be. Thus in the example code
  125. * above, the harness would test that document.documentElement correctly
  126. * implements HTMLHtmlElement, HTMLElement, Element, and Node; but
  127. * document.head would only be tested for HTMLHeadElement, and so on for
  128. * further objects.
  129. *
  130. * test():
  131. * Run all tests. This should be called after you've called all other
  132. * methods to add IDLs and objects.
  133. */
  134. /**
  135. * Notes for people who want to edit this file (not just use it as a library):
  136. *
  137. * Most of the interesting stuff happens in the derived classes of IdlObject,
  138. * especially IdlInterface. The entry point for all IdlObjects is .test(),
  139. * which is called by IdlArray.test(). An IdlObject is conceptually just
  140. * "thing we want to run tests on", and an IdlArray is an array of IdlObjects
  141. * with some additional data thrown in.
  142. *
  143. * The object model is based on what WebIDLParser.js produces, which is in turn
  144. * based on its pegjs grammar. If you want to figure out what properties an
  145. * object will have from WebIDLParser.js, the best way is to look at the
  146. * grammar:
  147. *
  148. * https://github.com/darobin/webidl.js/blob/master/lib/grammar.peg
  149. *
  150. * So for instance:
  151. *
  152. * // interface definition
  153. * interface
  154. * = extAttrs:extendedAttributeList? S? "interface" S name:identifier w herit:ifInheritance? w "{" w mem:ifMember* w "}" w ";" w
  155. * { return { type: "interface", name: name, inheritance: herit, members: mem, extAttrs: extAttrs }; }
  156. *
  157. * This means that an "interface" object will have a .type property equal to
  158. * the string "interface", a .name property equal to the identifier that the
  159. * parser found, an .inheritance property equal to either null or the result of
  160. * the "ifInheritance" production found elsewhere in the grammar, and so on.
  161. * After each grammatical production is a JavaScript function in curly braces
  162. * that gets called with suitable arguments and returns some JavaScript value.
  163. *
  164. * (Note that the version of WebIDLParser.js we use might sometimes be
  165. * out-of-date or forked.)
  166. *
  167. * The members and methods of the classes defined by this file are all at least
  168. * briefly documented, hopefully.
  169. */
  170. (function(){
  171. "use strict";
  172. /// Helpers ///
  173. function constValue (cnt) {
  174. if (cnt.type === "null") return null;
  175. if (cnt.type === "NaN") return NaN;
  176. if (cnt.type === "Infinity") return cnt.negative ? -Infinity : Infinity;
  177. return cnt.value;
  178. }
  179. /// IdlArray ///
  180. // Entry point
  181. window.IdlArray = function()
  182. //@{
  183. {
  184. /**
  185. * A map from strings to the corresponding named IdlObject, such as
  186. * IdlInterface or IdlException. These are the things that test() will run
  187. * tests on.
  188. */
  189. this.members = {};
  190. /**
  191. * A map from strings to arrays of strings. The keys are interface or
  192. * exception names, and are expected to also exist as keys in this.members
  193. * (otherwise they'll be ignored). This is populated by add_objects() --
  194. * see documentation at the start of the file. The actual tests will be
  195. * run by calling this.members[name].test_object(obj) for each obj in
  196. * this.objects[name]. obj is a string that will be eval'd to produce a
  197. * JavaScript value, which is supposed to be an object implementing the
  198. * given IdlObject (interface, exception, etc.).
  199. */
  200. this.objects = {};
  201. /**
  202. * When adding multiple collections of IDLs one at a time, an earlier one
  203. * might contain a partial interface or implements statement that depends
  204. * on a later one. Save these up and handle them right before we run
  205. * tests.
  206. *
  207. * .partials is simply an array of objects from WebIDLParser.js'
  208. * "partialinterface" production. .implements maps strings to arrays of
  209. * strings, such that
  210. *
  211. * A implements B;
  212. * A implements C;
  213. * D implements E;
  214. *
  215. * results in { A: ["B", "C"], D: ["E"] }.
  216. */
  217. this.partials = [];
  218. this["implements"] = {};
  219. };
  220. //@}
  221. IdlArray.prototype.add_idls = function(raw_idls)
  222. //@{
  223. {
  224. /** Entry point. See documentation at beginning of file. */
  225. this.internal_add_idls(WebIDL2.parse(raw_idls));
  226. };
  227. //@}
  228. IdlArray.prototype.add_untested_idls = function(raw_idls)
  229. //@{
  230. {
  231. /** Entry point. See documentation at beginning of file. */
  232. var parsed_idls = WebIDL2.parse(raw_idls);
  233. for (var i = 0; i < parsed_idls.length; i++)
  234. {
  235. parsed_idls[i].untested = true;
  236. if ("members" in parsed_idls[i])
  237. {
  238. for (var j = 0; j < parsed_idls[i].members.length; j++)
  239. {
  240. parsed_idls[i].members[j].untested = true;
  241. }
  242. }
  243. }
  244. this.internal_add_idls(parsed_idls);
  245. };
  246. //@}
  247. IdlArray.prototype.internal_add_idls = function(parsed_idls)
  248. //@{
  249. {
  250. /**
  251. * Internal helper called by add_idls() and add_untested_idls().
  252. * parsed_idls is an array of objects that come from WebIDLParser.js's
  253. * "definitions" production. The add_untested_idls() entry point
  254. * additionally sets an .untested property on each object (and its
  255. * .members) so that they'll be skipped by test() -- they'll only be
  256. * used for base interfaces of tested interfaces, return types, etc.
  257. */
  258. parsed_idls.forEach(function(parsed_idl)
  259. {
  260. if (parsed_idl.type == "interface" && parsed_idl.partial)
  261. {
  262. this.partials.push(parsed_idl);
  263. return;
  264. }
  265. if (parsed_idl.type == "implements")
  266. {
  267. if (!(parsed_idl.target in this["implements"]))
  268. {
  269. this["implements"][parsed_idl.target] = [];
  270. }
  271. this["implements"][parsed_idl.target].push(parsed_idl["implements"]);
  272. return;
  273. }
  274. parsed_idl.array = this;
  275. if (parsed_idl.name in this.members)
  276. {
  277. throw "Duplicate identifier " + parsed_idl.name;
  278. }
  279. switch(parsed_idl.type)
  280. {
  281. case "interface":
  282. this.members[parsed_idl.name] = new IdlInterface(parsed_idl);
  283. break;
  284. case "exception":
  285. this.members[parsed_idl.name] = new IdlException(parsed_idl);
  286. break;
  287. case "dictionary":
  288. // Nothing to test, but we need the dictionary info around for type
  289. // checks
  290. this.members[parsed_idl.name] = new IdlDictionary(parsed_idl);
  291. break;
  292. case "typedef":
  293. // TODO
  294. console.log("typedef not yet supported");
  295. break;
  296. case "callback":
  297. // TODO
  298. console.log("callback not yet supported");
  299. break;
  300. case "enum":
  301. this.members[parsed_idl.name] = new IdlEnum(parsed_idl);
  302. break;
  303. case "callback":
  304. // TODO
  305. break;
  306. default:
  307. throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported";
  308. }
  309. }.bind(this));
  310. };
  311. //@}
  312. IdlArray.prototype.add_objects = function(dict)
  313. //@{
  314. {
  315. /** Entry point. See documentation at beginning of file. */
  316. for (var k in dict)
  317. {
  318. if (k in this.objects)
  319. {
  320. this.objects[k] = this.objects[k].concat(dict[k]);
  321. }
  322. else
  323. {
  324. this.objects[k] = dict[k];
  325. }
  326. }
  327. };
  328. //@}
  329. IdlArray.prototype.prevent_multiple_testing = function(name)
  330. //@{
  331. {
  332. /** Entry point. See documentation at beginning of file. */
  333. this.members[name].prevent_multiple_testing = true;
  334. };
  335. //@}
  336. IdlArray.prototype.recursively_get_implements = function(interface_name)
  337. //@{
  338. {
  339. /**
  340. * Helper function for test(). Returns an array of things that implement
  341. * interface_name, so if the IDL contains
  342. *
  343. * A implements B;
  344. * B implements C;
  345. * B implements D;
  346. *
  347. * then recursively_get_implements("A") should return ["B", "C", "D"].
  348. */
  349. var ret = this["implements"][interface_name];
  350. if (ret === undefined)
  351. {
  352. return [];
  353. }
  354. for (var i = 0; i < this["implements"][interface_name].length; i++)
  355. {
  356. ret = ret.concat(this.recursively_get_implements(ret[i]));
  357. if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i]))
  358. {
  359. throw "Circular implements statements involving " + ret[i];
  360. }
  361. }
  362. return ret;
  363. };
  364. //@}
  365. IdlArray.prototype.test = function()
  366. //@{
  367. {
  368. /** Entry point. See documentation at beginning of file. */
  369. // First merge in all the partial interfaces and implements statements we
  370. // encountered.
  371. this.partials.forEach(function(parsed_idl)
  372. {
  373. if (!(parsed_idl.name in this.members)
  374. || !(this.members[parsed_idl.name] instanceof IdlInterface))
  375. {
  376. throw "Partial interface " + parsed_idl.name + " with no original interface";
  377. }
  378. if (parsed_idl.extAttrs)
  379. {
  380. parsed_idl.extAttrs.forEach(function(extAttr)
  381. {
  382. this.members[parsed_idl.name].extAttrs.push(extAttr);
  383. }.bind(this));
  384. }
  385. parsed_idl.members.forEach(function(member)
  386. {
  387. this.members[parsed_idl.name].members.push(new IdlInterfaceMember(member));
  388. }.bind(this));
  389. }.bind(this));
  390. this.partials = [];
  391. for (var lhs in this["implements"])
  392. {
  393. this.recursively_get_implements(lhs).forEach(function(rhs)
  394. {
  395. var errStr = lhs + " implements " + rhs + ", but ";
  396. if (!(lhs in this.members)) throw errStr + lhs + " is undefined.";
  397. if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface.";
  398. if (!(rhs in this.members)) throw errStr + rhs + " is undefined.";
  399. if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface.";
  400. this.members[rhs].members.forEach(function(member)
  401. {
  402. this.members[lhs].members.push(new IdlInterfaceMember(member));
  403. }.bind(this));
  404. }.bind(this));
  405. }
  406. this["implements"] = {};
  407. // Now run test() on every member, and test_object() for every object.
  408. for (var name in this.members)
  409. {
  410. this.members[name].test();
  411. if (name in this.objects)
  412. {
  413. this.objects[name].forEach(function(str)
  414. {
  415. this.members[name].test_object(str);
  416. }.bind(this));
  417. }
  418. }
  419. };
  420. //@}
  421. IdlArray.prototype.assert_type_is = function(value, type)
  422. //@{
  423. {
  424. /**
  425. * Helper function that tests that value is an instance of type according
  426. * to the rules of WebIDL. value is any JavaScript value, and type is an
  427. * object produced by WebIDLParser.js' "type" production. That production
  428. * is fairly elaborate due to the complexity of WebIDL's types, so it's
  429. * best to look at the grammar to figure out what properties it might have.
  430. */
  431. if (type.idlType == "any")
  432. {
  433. // No assertions to make
  434. return;
  435. }
  436. if (type.nullable && value === null)
  437. {
  438. // This is fine
  439. return;
  440. }
  441. if (type.array)
  442. {
  443. // TODO: not supported yet
  444. return;
  445. }
  446. if (type.sequence)
  447. {
  448. assert_true(Array.isArray(value), "is not array");
  449. if (!value.length)
  450. {
  451. // Nothing we can do.
  452. return;
  453. }
  454. this.assert_type_is(value[0], type.idlType.idlType);
  455. return;
  456. }
  457. type = type.idlType;
  458. switch(type)
  459. {
  460. case "void":
  461. assert_equals(value, undefined);
  462. return;
  463. case "boolean":
  464. assert_equals(typeof value, "boolean");
  465. return;
  466. case "byte":
  467. assert_equals(typeof value, "number");
  468. assert_equals(value, Math.floor(value), "not an integer");
  469. assert_true(-128 <= value && value <= 127, "byte " + value + " not in range [-128, 127]");
  470. return;
  471. case "octet":
  472. assert_equals(typeof value, "number");
  473. assert_equals(value, Math.floor(value), "not an integer");
  474. assert_true(0 <= value && value <= 255, "octet " + value + " not in range [0, 255]");
  475. return;
  476. case "short":
  477. assert_equals(typeof value, "number");
  478. assert_equals(value, Math.floor(value), "not an integer");
  479. assert_true(-32768 <= value && value <= 32767, "short " + value + " not in range [-32768, 32767]");
  480. return;
  481. case "unsigned short":
  482. assert_equals(typeof value, "number");
  483. assert_equals(value, Math.floor(value), "not an integer");
  484. assert_true(0 <= value && value <= 65535, "unsigned short " + value + " not in range [0, 65535]");
  485. return;
  486. case "long":
  487. assert_equals(typeof value, "number");
  488. assert_equals(value, Math.floor(value), "not an integer");
  489. assert_true(-2147483648 <= value && value <= 2147483647, "long " + value + " not in range [-2147483648, 2147483647]");
  490. return;
  491. case "unsigned long":
  492. assert_equals(typeof value, "number");
  493. assert_equals(value, Math.floor(value), "not an integer");
  494. assert_true(0 <= value && value <= 4294967295, "unsigned long " + value + " not in range [0, 4294967295]");
  495. return;
  496. case "long long":
  497. assert_equals(typeof value, "number");
  498. return;
  499. case "unsigned long long":
  500. assert_equals(typeof value, "number");
  501. assert_true(0 <= value, "unsigned long long is negative");
  502. return;
  503. case "float":
  504. case "double":
  505. // TODO: distinguish these cases
  506. assert_equals(typeof value, "number");
  507. return;
  508. case "DOMString":
  509. assert_equals(typeof value, "string");
  510. return;
  511. case "object":
  512. assert_true(typeof value == "object" || typeof value == "function", "wrong type: not object or function");
  513. return;
  514. }
  515. if (!(type in this.members))
  516. {
  517. throw "Unrecognized type " + type;
  518. }
  519. if (this.members[type] instanceof IdlInterface)
  520. {
  521. // We don't want to run the full
  522. // IdlInterface.prototype.test_instance_of, because that could result
  523. // in an infinite loop. TODO: This means we don't have tests for
  524. // NoInterfaceObject interfaces, and we also can't test objects that
  525. // come from another window.
  526. assert_true(typeof value == "object" || typeof value == "function", "wrong type: not object or function");
  527. if (value instanceof Object
  528. && !this.members[type].has_extended_attribute("NoInterfaceObject")
  529. && type in window)
  530. {
  531. assert_true(value instanceof window[type], "not instanceof " + type);
  532. }
  533. }
  534. else if (this.members[type] instanceof IdlEnum)
  535. {
  536. assert_equals(typeof value, "string");
  537. }
  538. else if (this.members[type] instanceof IdlDictionary)
  539. {
  540. // TODO: Test when we actually have something to test this on
  541. }
  542. else
  543. {
  544. throw "Type " + type + " isn't an interface or dictionary";
  545. }
  546. };
  547. //@}
  548. /// IdlObject ///
  549. function IdlObject() {}
  550. IdlObject.prototype.test = function()
  551. //@{
  552. {
  553. /**
  554. * By default, this does nothing, so no actual tests are run for IdlObjects
  555. * that don't define any (e.g., IdlDictionary at the time of this writing).
  556. */
  557. };
  558. //@}
  559. IdlObject.prototype.has_extended_attribute = function(name)
  560. //@{
  561. {
  562. /**
  563. * This is only meaningful for things that support extended attributes,
  564. * such as interfaces, exceptions, and members.
  565. */
  566. return this.extAttrs.some(function(o)
  567. {
  568. return o.name == name;
  569. });
  570. };
  571. //@}
  572. /// IdlDictionary ///
  573. // Used for IdlArray.prototype.assert_type_is
  574. function IdlDictionary(obj)
  575. //@{
  576. {
  577. /**
  578. * obj is an object produced by the WebIDLParser.js "dictionary"
  579. * production.
  580. */
  581. /** Self-explanatory. */
  582. this.name = obj.name;
  583. /** An array of objects produced by the "dictionaryMember" production. */
  584. this.members = obj.members;
  585. /**
  586. * The name (as a string) of the dictionary type we inherit from, or null
  587. * if there is none.
  588. */
  589. this.base = obj.inheritance;
  590. }
  591. //@}
  592. IdlDictionary.prototype = Object.create(IdlObject.prototype);
  593. /// IdlExceptionOrInterface ///
  594. // Code sharing!
  595. function IdlExceptionOrInterface(obj)
  596. //@{
  597. {
  598. /**
  599. * obj is an object produced by the WebIDLParser.js "exception" or
  600. * "interface" production, as appropriate.
  601. */
  602. /** Self-explanatory. */
  603. this.name = obj.name;
  604. /** A back-reference to our IdlArray. */
  605. this.array = obj.array;
  606. /**
  607. * An indicator of whether we should run tests on the (exception) interface
  608. * object and (exception) interface prototype object. Tests on members are
  609. * controlled by .untested on each member, not this.
  610. */
  611. this.untested = obj.untested;
  612. /** An array of objects produced by the "ExtAttr" production. */
  613. this.extAttrs = obj.extAttrs;
  614. /** An array of IdlInterfaceMembers. */
  615. this.members = obj.members.map(function(m){return new IdlInterfaceMember(m); });
  616. /**
  617. * The name (as a string) of the type we inherit from, or null if there is
  618. * none.
  619. */
  620. this.base = obj.inheritance;
  621. }
  622. //@}
  623. IdlExceptionOrInterface.prototype = Object.create(IdlObject.prototype);
  624. IdlExceptionOrInterface.prototype.test = function()
  625. //@{
  626. {
  627. if (this.has_extended_attribute("NoInterfaceObject"))
  628. {
  629. // No tests to do without an instance. TODO: We should still be able
  630. // to run tests on the prototype object, if we obtain one through some
  631. // other means.
  632. return;
  633. }
  634. if (!this.untested)
  635. {
  636. // First test things to do with the exception/interface object and
  637. // exception/interface prototype object.
  638. this.test_self();
  639. }
  640. // Then test things to do with its members (constants, fields, attributes,
  641. // operations, . . .). These are run even if .untested is true, because
  642. // members might themselves be marked as .untested. This might happen to
  643. // interfaces if the interface itself is untested but a partial interface
  644. // that extends it is tested -- then the interface itself and its initial
  645. // members will be marked as untested, but the members added by the partial
  646. // interface are still tested.
  647. this.test_members();
  648. };
  649. //@}
  650. /// IdlException ///
  651. function IdlException(obj) { IdlExceptionOrInterface.call(this, obj); }
  652. IdlException.prototype = Object.create(IdlExceptionOrInterface.prototype);
  653. IdlException.prototype.test_self = function()
  654. //@{
  655. {
  656. test(function()
  657. {
  658. // "For every exception that is not declared with the
  659. // [NoInterfaceObject] extended attribute, a corresponding property
  660. // must exist on the exception’s relevant namespace object. The name of
  661. // the property is the identifier of the exception, and its value is an
  662. // object called the exception interface object, which provides access
  663. // to any constants that have been associated with the exception. The
  664. // property has the attributes { [[Writable]]: true, [[Enumerable]]:
  665. // false, [[Configurable]]: true }."
  666. assert_own_property(window, this.name,
  667. "window does not have own property " + format_value(this.name));
  668. var desc = Object.getOwnPropertyDescriptor(window, this.name);
  669. assert_false("get" in desc, "window's property " + format_value(this.name) + " has getter");
  670. assert_false("set" in desc, "window's property " + format_value(this.name) + " has setter");
  671. assert_true(desc.writable, "window's property " + format_value(this.name) + " is not writable");
  672. assert_false(desc.enumerable, "window's property " + format_value(this.name) + " is enumerable");
  673. assert_true(desc.configurable, "window's property " + format_value(this.name) + " is not configurable");
  674. // "The exception interface object for a given exception must be a
  675. // function object."
  676. // "If an object is defined to be a function object, then it has
  677. // characteristics as follows:"
  678. // "Its [[Prototype]] internal property is the Function prototype
  679. // object."
  680. // Note: This doesn't match browsers as of December 2011, see
  681. // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14813
  682. assert_equals(Object.getPrototypeOf(window[this.name]), Function.prototype,
  683. "prototype of window's property " + format_value(this.name) + " is not Function.prototype");
  684. // "Its [[Get]] internal property is set as described in ECMA-262
  685. // section 15.3.5.4."
  686. // Not much to test for this.
  687. // "Its [[Construct]] internal property is set as described in ECMA-262
  688. // section 13.2.2."
  689. // Tested below.
  690. // "Its [[HasInstance]] internal property is set as described in
  691. // ECMA-262 section 15.3.5.3, unless otherwise specified."
  692. // TODO
  693. // "Its [[Class]] internal property is “Function”."
  694. // String() returns something implementation-dependent, because it
  695. // calls Function#toString.
  696. assert_class_string(window[this.name], "Function",
  697. "class string of " + this.name);
  698. // TODO: Test 4.9.1.1. Exception interface object [[Call]] method
  699. // (which does not match browsers:
  700. // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14885)
  701. }.bind(this), this.name + " exception: existence and properties of exception interface object");
  702. test(function()
  703. {
  704. assert_own_property(window, this.name,
  705. "window does not have own property " + format_value(this.name));
  706. // "The exception interface object must also have a property named
  707. // “prototype” with attributes { [[Writable]]: false, [[Enumerable]]:
  708. // false, [[Configurable]]: false } whose value is an object called the
  709. // exception interface prototype object. This object also provides
  710. // access to the constants that are declared on the exception."
  711. assert_own_property(window[this.name], "prototype",
  712. 'exception "' + this.name + '" does not have own property "prototype"');
  713. var desc = Object.getOwnPropertyDescriptor(window[this.name], "prototype");
  714. assert_false("get" in desc, this.name + ".prototype has getter");
  715. assert_false("set" in desc, this.name + ".prototype has setter");
  716. assert_false(desc.writable, this.name + ".prototype is writable");
  717. assert_false(desc.enumerable, this.name + ".prototype is enumerable");
  718. assert_false(desc.configurable, this.name + ".prototype is configurable");
  719. // "The exception interface prototype object for a given exception must
  720. // have an internal [[Prototype]] property whose value is as follows:
  721. //
  722. // "If the exception is declared to inherit from another exception,
  723. // then the value of the internal [[Prototype]] property is the
  724. // exception interface prototype object for the inherited exception.
  725. // "Otherwise, the exception is not declared to inherit from another
  726. // exception. The value of the internal [[Prototype]] property is the
  727. // Error prototype object ([ECMA-262], section 15.11.3.1)."
  728. //
  729. // Note: This doesn't match browsers as of December 2011, see
  730. // https://www.w3.org/Bugs/Public/show_bug.cgi?id=14887.
  731. var inherit_exception = this.base ? this.base : "Error";
  732. assert_own_property(window, inherit_exception,
  733. 'should inherit from ' + inherit_exception + ', but window has no such property');
  734. assert_own_property(window[inherit_exception], "prototype",
  735. 'should inherit from ' + inherit_exception + ', but that object has no "prototype" property');
  736. assert_equals(Object.getPrototypeOf(window[this.name].prototype),
  737. window[inherit_exception].prototype,
  738. 'prototype of ' + this.name + '.prototype is not ' + inherit_exception + '.prototype');
  739. // "The class string of an exception interface prototype object is the
  740. // concatenation of the exception’s identifier and the string
  741. // “Prototype”."
  742. assert_class_string(window[this.name].prototype, this.name + "Prototype",
  743. "class string of " + this.name + ".prototype");
  744. // TODO: Test String(), based on ES definition of
  745. // Error.prototype.toString?
  746. }.bind(this), this.name + " exception: existence and properties of exception interface prototype object");
  747. test(function()
  748. {
  749. assert_own_property(window, this.name,
  750. "window does not have own property " + format_value(this.name));
  751. assert_own_property(window[this.name], "prototype",
  752. 'interface "' + this.name + '" does not have own property "prototype"');
  753. // "There must be a property named “name” on the exception interface
  754. // prototype object with attributes { [[Writable]]: true,
  755. // [[Enumerable]]: false, [[Configurable]]: true } and whose value is
  756. // the identifier of the exception."
  757. assert_own_property(window[this.name].prototype, "name",
  758. 'prototype object does not have own property "name"');
  759. var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "name");
  760. assert_false("get" in desc, this.name + ".prototype.name has getter");
  761. assert_false("set" in desc, this.name + ".prototype.name has setter");
  762. assert_true(desc.writable, this.name + ".prototype.name is not writable");
  763. assert_false(desc.enumerable, this.name + ".prototype.name is enumerable");
  764. assert_true(desc.configurable, this.name + ".prototype.name is not configurable");
  765. assert_equals(desc.value, this.name, this.name + ".prototype.name has incorrect value");
  766. }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"name\" property");
  767. test(function()
  768. {
  769. assert_own_property(window, this.name,
  770. "window does not have own property " + format_value(this.name));
  771. assert_own_property(window[this.name], "prototype",
  772. 'interface "' + this.name + '" does not have own property "prototype"');
  773. // "If the [NoInterfaceObject] extended attribute was not specified on
  774. // the exception, then there must also be a property named
  775. // “constructor” on the exception interface prototype object with
  776. // attributes { [[Writable]]: true, [[Enumerable]]: false,
  777. // [[Configurable]]: true } and whose value is a reference to the
  778. // exception interface object for the exception."
  779. assert_own_property(window[this.name].prototype, "constructor",
  780. this.name + '.prototype does not have own property "constructor"');
  781. var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "constructor");
  782. assert_false("get" in desc, this.name + ".prototype.constructor has getter");
  783. assert_false("set" in desc, this.name + ".prototype.constructor has setter");
  784. assert_true(desc.writable, this.name + ".prototype.constructor is not writable");
  785. assert_false(desc.enumerable, this.name + ".prototype.constructor is enumerable");
  786. assert_true(desc.configurable, this.name + ".prototype.constructor in not configurable");
  787. assert_equals(window[this.name].prototype.constructor, window[this.name],
  788. this.name + '.prototype.constructor is not the same object as ' + this.name);
  789. }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"constructor\" property");
  790. };
  791. //@}
  792. IdlException.prototype.test_members = function()
  793. //@{
  794. {
  795. for (var i = 0; i < this.members.length; i++)
  796. {
  797. var member = this.members[i];
  798. if (member.untested)
  799. {
  800. continue;
  801. }
  802. if (member.type == "const" && member.name != "prototype")
  803. {
  804. test(function()
  805. {
  806. assert_own_property(window, this.name,
  807. "window does not have own property " + format_value(this.name));
  808. // "For each constant defined on the exception, there must be a
  809. // corresponding property on the exception interface object, if
  810. // it exists, if the identifier of the constant is not
  811. // “prototype”."
  812. assert_own_property(window[this.name], member.name);
  813. // "The value of the property is the ECMAScript value that is
  814. // equivalent to the constant’s IDL value, according to the
  815. // rules in section 4.2 above."
  816. assert_equals(window[this.name][member.name], constValue(member.value),
  817. "property has wrong value");
  818. // "The property has attributes { [[Writable]]: false,
  819. // [[Enumerable]]: true, [[Configurable]]: false }."
  820. var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
  821. assert_false("get" in desc, "property has getter");
  822. assert_false("set" in desc, "property has setter");
  823. assert_false(desc.writable, "property is writable");
  824. assert_true(desc.enumerable, "property is not enumerable");
  825. assert_false(desc.configurable, "property is configurable");
  826. }.bind(this), this.name + " exception: constant " + member.name + " on exception interface object");
  827. // "In addition, a property with the same characteristics must
  828. // exist on the exception interface prototype object."
  829. test(function()
  830. {
  831. assert_own_property(window, this.name,
  832. "window does not have own property " + format_value(this.name));
  833. assert_own_property(window[this.name], "prototype",
  834. 'exception "' + this.name + '" does not have own property "prototype"');
  835. assert_own_property(window[this.name].prototype, member.name);
  836. assert_equals(window[this.name].prototype[member.name], constValue(member.value),
  837. "property has wrong value");
  838. var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, member.name);
  839. assert_false("get" in desc, "property has getter");
  840. assert_false("set" in desc, "property has setter");
  841. assert_false(desc.writable, "property is writable");
  842. assert_true(desc.enumerable, "property is not enumerable");
  843. assert_false(desc.configurable, "property is configurable");
  844. }.bind(this), this.name + " exception: constant " + member.name + " on exception interface prototype object");
  845. }
  846. else if (member.type == "field")
  847. {
  848. test(function()
  849. {
  850. assert_own_property(window, this.name,
  851. "window does not have own property " + format_value(this.name));
  852. assert_own_property(window[this.name], "prototype",
  853. 'exception "' + this.name + '" does not have own property "prototype"');
  854. // "For each exception field, there must be a corresponding
  855. // property on the exception interface prototype object, whose
  856. // characteristics are as follows:
  857. // "The name of the property is the identifier of the exception
  858. // field."
  859. assert_own_property(window[this.name].prototype, member.name);
  860. // "The property has attributes { [[Get]]: G, [[Enumerable]]:
  861. // true, [[Configurable]]: true }, where G is the exception
  862. // field getter, defined below."
  863. var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, member.name);
  864. assert_false("value" in desc, "property descriptor has value but is supposed to be accessor");
  865. assert_false("writable" in desc, 'property descriptor has "writable" field but is supposed to be accessor');
  866. // TODO: ES5 doesn't seem to say whether desc should have a
  867. // .set property.
  868. assert_true(desc.enumerable, "property is not enumerable");
  869. assert_true(desc.configurable, "property is not configurable");
  870. // "The exception field getter is a Function object whose
  871. // behavior when invoked is as follows:"
  872. assert_equals(typeof desc.get, "function", "typeof getter");
  873. // "The value of the Function object’s “length” property is the
  874. // Number value 0."
  875. // This test is before the TypeError tests so that it's easiest
  876. // to see that Firefox 11a1 only fails one assert in this test.
  877. assert_equals(desc.get.length, 0, "getter length");
  878. // "Let O be the result of calling ToObject on the this value.
  879. // "If O is not a platform object representing an exception for
  880. // the exception on which the exception field was declared,
  881. // then throw a TypeError."
  882. // TODO: Test on a platform object representing an exception.
  883. assert_throws(new TypeError(), function()
  884. {
  885. window[this.name].prototype[member.name];
  886. }.bind(this), "getting property on prototype object must throw TypeError");
  887. assert_throws(new TypeError(), function()
  888. {
  889. desc.get.call({});
  890. }.bind(this), "calling getter on wrong object type must throw TypeError");
  891. }.bind(this), this.name + " exception: field " + member.name + " on exception interface prototype object");
  892. }
  893. }
  894. };
  895. //@}
  896. IdlException.prototype.test_object = function(desc)
  897. //@{
  898. {
  899. var obj, exception = null;
  900. try
  901. {
  902. obj = eval(desc);
  903. }
  904. catch(e)
  905. {
  906. exception = e;
  907. }
  908. test(function()
  909. {
  910. assert_equals(exception, null, "Unexpected exception when evaluating object");
  911. assert_equals(typeof obj, "object", "wrong typeof object");
  912. // We can't easily test that its prototype is correct if there's no
  913. // interface object, or the object is from a different global
  914. // environment (not instanceof Object). TODO: test in this case that
  915. // its prototype at least looks correct, even if we can't test that
  916. // it's actually correct.
  917. if (!this.has_extended_attribute("NoInterfaceObject")
  918. && (typeof obj != "object" || obj instanceof Object))
  919. {
  920. assert_own_property(window, this.name,
  921. "window does not have own property " + format_value(this.name));
  922. assert_own_property(window[this.name], "prototype",
  923. 'exception "' + this.name + '" does not have own property "prototype"');
  924. // "The value of the internal [[Prototype]] property of the
  925. // exception object must be the exception interface prototype
  926. // object from the global environment the exception object is
  927. // associated with."
  928. assert_equals(Object.getPrototypeOf(obj),
  929. window[this.name].prototype,
  930. desc + "'s prototype is not " + this.name + ".prototype");
  931. }
  932. // "The class string of the exception object must be the identifier of
  933. // the exception."
  934. assert_class_string(obj, this.name, "class string of " + desc);
  935. // Stringifier is not defined for DOMExceptions, because message isn't
  936. // defined.
  937. }.bind(this), this.name + " must be represented by " + desc);
  938. for (var i = 0; i < this.members.length; i++)
  939. {
  940. var member = this.members[i];
  941. test(function()
  942. {
  943. assert_equals(exception, null, "Unexpected exception when evaluating object");
  944. assert_equals(typeof obj, "object", "wrong typeof object");
  945. assert_inherits(obj, member.name);
  946. if (member.type == "const")
  947. {
  948. assert_equals(obj[member.name], constValue(member.value));
  949. }
  950. if (member.type == "field")
  951. {
  952. this.array.assert_type_is(obj[member.name], member.idlType);
  953. }
  954. }.bind(this), this.name + " exception: " + desc + ' must inherit property "' + member.name + '" with the proper type');
  955. }
  956. };
  957. //@}
  958. /// IdlInterface ///
  959. function IdlInterface(obj) { IdlExceptionOrInterface.call(this, obj); }
  960. IdlInterface.prototype = Object.create(IdlExceptionOrInterface.prototype);
  961. IdlInterface.prototype.is_callback = function()
  962. //@{
  963. {
  964. return this.has_extended_attribute("Callback");
  965. };
  966. //@}
  967. IdlInterface.prototype.has_constants = function()
  968. //@{
  969. {
  970. return this.members.any(function(member) {
  971. return member.type === "const";
  972. });
  973. };
  974. //@}
  975. IdlInterface.prototype.test_self = function()
  976. //@{
  977. {
  978. test(function()
  979. {
  980. // This function tests WebIDL as of 2012-11-28.
  981. // "For every interface that:
  982. // * is a callback interface that has constants declared on it, or
  983. // * is a non-callback interface that is not declared with the
  984. // [NoInterfaceObject] extended attribute,
  985. // a corresponding property MUST exist on the ECMAScript global object.
  986. // The name of the property is the identifier of the interface, and its
  987. // value is an object called the interface object.
  988. // The property has the attributes { [[Writable]]: true,
  989. // [[Enumerable]]: false, [[Configurable]]: true }."
  990. if (this.is_callback() && !this.has_constants()) {
  991. return;
  992. }
  993. // TODO: Should we test here that the property is actually writable
  994. // etc., or trust getOwnPropertyDescriptor?
  995. assert_own_property(window, this.name,
  996. "window does not have own property " + format_value(this.name));
  997. var desc = Object.getOwnPropertyDescriptor(window, this.name);
  998. assert_false("get" in desc, "window's property " + format_value(this.name) + " has getter");
  999. assert_false("set" in desc, "window's property " + format_value(this.name) + " has setter");
  1000. assert_true(desc.writable, "window's property " + format_value(this.name) + " is not writable");
  1001. assert_false(desc.enumerable, "window's property " + format_value(this.name) + " is enumerable");
  1002. assert_true(desc.configurable, "window's property " + format_value(this.name) + " is not configurable");
  1003. if (this.is_callback()) {
  1004. // "The internal [[Prototype]] property of an interface object for
  1005. // a callback interface MUST be the Object.prototype object."
  1006. assert_equals(Object.getPrototypeOf(window[this.name]), Object.prototype,
  1007. "prototype of window's property " + format_value(this.name) + " is not Object.prototype");
  1008. return;
  1009. }
  1010. // "The interface object for a given non-callback interface is a
  1011. // function object."
  1012. // "If an object is defined to be a function object, then it has
  1013. // characteristics as follows:"
  1014. // "* Its [[Prototype]] internal property is the Function prototype
  1015. // object."
  1016. assert_equals(Object.getPrototypeOf(window[this.name]), Function.prototype,
  1017. "prototype of window's property " + format_value(this.name) + " is not Function.prototype");
  1018. // "* Its [[Get]] internal property is set as described in ECMA-262
  1019. // section 15.3.5.4."
  1020. // Not much to test for this.
  1021. // "* Its [[Construct]] internal property is set as described in
  1022. // ECMA-262 section 13.2.2."
  1023. // Tested below if no constructor is defined. TODO: test constructors
  1024. // if defined.
  1025. // "* Its [[HasInstance]] internal property is set as described in
  1026. // ECMA-262 section 15.3.5.3, unless otherwise specified."
  1027. // TODO
  1028. // "* Its [[NativeBrand]] internal property is “Function”."
  1029. // String() returns something implementation-dependent, because it calls
  1030. // Function#toString.
  1031. assert_class_string(window[this.name], "Function", "class string of " + this.name);
  1032. if (!this.has_extended_attribute("Constructor")) {
  1033. // "The internal [[Call]] method of the interface object behaves as
  1034. // follows . . .
  1035. //
  1036. // "If I was not declared with a [Constructor] extended attribute,
  1037. // then throw a TypeError."
  1038. assert_throws(new TypeError(), function() {
  1039. window[this.name]();
  1040. }.bind(this), "interface object didn't throw TypeError when called as a function");
  1041. assert_throws(new TypeError(), function() {
  1042. new window[this.name]();
  1043. }.bind(this), "interface object didn't throw TypeError when called as a constructor");
  1044. }
  1045. }.bind(this), this.name + " interface: existence and properties of interface object");
  1046. if (this.has_extended_attribute("Constructor"))
  1047. {
  1048. test(function()
  1049. {
  1050. assert_own_property(window, this.name,
  1051. "window does not have own property " + format_value(this.name));
  1052. // "Interface objects for interfaces declared with a [Constructor]
  1053. // extended attribute must have a property named “length” with
  1054. // attributes { [[Writable]]: false, [[Enumerable]]: false,
  1055. // [[Configurable]]: false } whose value is a Number determined as
  1056. // follows: . . .
  1057. // "Return the length of the shortest argument list of the entries
  1058. // in S."
  1059. // TODO: Variadic constructors. Should generalize this so that it
  1060. // works for testing operation length too (currently we just don't
  1061. // support multiple operations with the same identifier).
  1062. var expected_length = this.extAttrs
  1063. .filter(function(attr) { return attr.name == "Constructor"; })
  1064. .map(function(attr) {
  1065. return attr.arguments ? attr.arguments.filter(
  1066. function(arg) {
  1067. return !arg.optional;
  1068. }).length : 0;
  1069. })
  1070. .reduce(function(m, n) { return Math.min(m, n); });
  1071. assert_own_property(window[this.name], "length");
  1072. assert_equals(window[this.name].length, expected_length, "wrong value for " + this.name + ".length");
  1073. var desc = Object.getOwnPropertyDescriptor(window[this.name], "length");
  1074. assert_false("get" in desc, this.name + ".length has getter");
  1075. assert_false("set" in desc, this.name + ".length has setter");
  1076. assert_false(desc.writable, this.name + ".length is writable");
  1077. assert_false(desc.enumerable, this.name + ".length is enumerable");
  1078. assert_false(desc.configurable, this.name + ".length is configurable");
  1079. }.bind(this), this.name + " interface constructor");
  1080. }
  1081. // TODO: Test named constructors if I find any interfaces that have them.
  1082. test(function()
  1083. {
  1084. assert_own_property(window, this.name,
  1085. "window does not have own property " + format_value(this.name));
  1086. if (this.has_extended_attribute("Callback")) {
  1087. assert_false("prototype" in window[this.name],
  1088. this.name + ' should not have a "prototype" property');
  1089. return;
  1090. }
  1091. // "The interface object must also have a property named “prototype”
  1092. // with attributes { [[Writable]]: false, [[Enumerable]]: false,
  1093. // [[Configurable]]: false } whose value is an object called the
  1094. // interface prototype object. This object has properties that
  1095. // correspond to the attributes and operations defined on the
  1096. // interface, and is described in more detail in section 4.5.3 below."
  1097. assert_own_property(window[this.name], "prototype",
  1098. 'interface "' + this.name + '" does not have own property "prototype"');
  1099. var desc = Object.getOwnPropertyDescriptor(window[this.name], "prototype");
  1100. assert_false("get" in desc, this.name + ".prototype has getter");
  1101. assert_false("set" in desc, this.name + ".prototype has setter");
  1102. assert_false(desc.writable, this.name + ".prototype is writable");
  1103. assert_false(desc.enumerable, this.name + ".prototype is enumerable");
  1104. assert_false(desc.configurable, this.name + ".prototype is configurable");
  1105. // Next, test that the [[Prototype]] of the interface prototype object
  1106. // is correct. (This is made somewhat difficult by the existence of
  1107. // [NoInterfaceObject].)
  1108. // TODO: Aryeh thinks there's at least other place in this file where
  1109. // we try to figure out if an interface prototype object is
  1110. // correct. Consolidate that code.
  1111. // "The interface prototype object for a given interface A must have an
  1112. // internal [[Prototype]] property whose value is as follows:
  1113. // "If A is not declared to inherit from another interface, then the
  1114. // value of the internal [[Prototype]] property of A is the Array
  1115. // prototype object ([ECMA-262], section 15.4.4) if the interface was
  1116. // declared with ArrayClass, or the Object prototype object otherwise
  1117. // ([ECMA-262], section 15.2.4).
  1118. // "Otherwise, A does inherit from another interface. The value of the
  1119. // internal [[Prototype]] property of A is the interface prototype
  1120. // object for the inherited interface."
  1121. var inherit_interface, inherit_interface_has_interface_object;
  1122. if (this.base) {
  1123. inherit_interface = this.base;
  1124. inherit_interface_has_interface_object =
  1125. !this.array
  1126. .members[inherit_interface]
  1127. .has_extended_attribute("NoInterfaceObject");
  1128. } else if (this.has_extended_attribute('ArrayClass')) {
  1129. inherit_interface = 'Array';
  1130. inherit_interface_has_interface_object = true;
  1131. } else {
  1132. inherit_interface = 'Object';
  1133. inherit_interface_has_interface_object = true;
  1134. }
  1135. if (inherit_interface_has_interface_object) {
  1136. assert_own_property(window, inherit_interface,
  1137. 'should inherit from ' + inherit_interface + ', but window has no such property');
  1138. assert_own_property(window[inherit_interface], 'prototype',
  1139. 'should inherit from ' + inherit_interface + ', but that object has no "prototype" property');
  1140. assert_equals(Object.getPrototypeOf(window[this.name].prototype),
  1141. window[inherit_interface].prototype,
  1142. 'prototype of ' + this.name + '.prototype is not ' + inherit_interface + '.prototype');
  1143. } else {
  1144. // We can't test that we get the correct object, because this is the
  1145. // only way to get our hands on it. We only test that its class
  1146. // string, at least, is correct.
  1147. assert_class_string(Object.getPrototypeOf(window[this.name].prototype),
  1148. inherit_interface + 'Prototype',
  1149. 'Class name for prototype of ' + this.name +
  1150. '.prototype is not "' + inherit_interface + 'Prototype"');
  1151. }
  1152. // "The class string of an interface prototype object is the
  1153. // concatenation of the interface’s identifier and the string
  1154. // “Prototype”."
  1155. assert_class_string(window[this.name].prototype, this.name + "Prototype",
  1156. "class string of " + this.name + ".prototype");
  1157. // String() should end up calling {}.toString if nothing defines a
  1158. // stringifier.
  1159. if (!this.has_stringifier()) {
  1160. assert_equals(String(window[this.name].prototype), "[object " + this.name + "Prototype]",
  1161. "String(" + this.name + ".prototype)");
  1162. }
  1163. }.bind(this), this.name + " interface: existence and properties of interface prototype object");
  1164. test(function()
  1165. {
  1166. assert_own_property(window, this.name,
  1167. "window does not have own property " + format_value(this.name));
  1168. if (this.has_extended_attribute("Callback")) {
  1169. assert_false("prototype" in window[this.name],
  1170. this.name + ' should not have a "prototype" property');
  1171. return;
  1172. }
  1173. assert_own_property(window[this.name], "prototype",
  1174. 'interface "' + this.name + '" does not have own property "prototype"');
  1175. // "If the [NoInterfaceObject] extended attribute was not specified on
  1176. // the interface, then the interface prototype object must also have a
  1177. // property named “constructor” with attributes { [[Writable]]: true,
  1178. // [[Enumerable]]: false, [[Configurable]]: true } whose value is a
  1179. // reference to the interface object for the interface."
  1180. assert_own_property(window[this.name].prototype, "constructor",
  1181. this.name + '.prototype does not have own property "constructor"');
  1182. var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "constructor");
  1183. assert_false("get" in desc, this.name + ".prototype.constructor has getter");
  1184. assert_false("set" in desc, this.name + ".prototype.constructor has setter");
  1185. assert_true(desc.writable, this.name + ".prototype.constructor is not writable");
  1186. assert_false(desc.enumerable, this.name + ".prototype.constructor is enumerable");
  1187. assert_true(desc.configurable, this.name + ".prototype.constructor in not configurable");
  1188. assert_equals(window[this.name].prototype.constructor, window[this.name],
  1189. this.name + '.prototype.constructor is not the same object as ' + this.name);
  1190. }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property');
  1191. };
  1192. //@}
  1193. IdlInterface.prototype.test_members = function()
  1194. //@{
  1195. {
  1196. for (var i = 0; i < this.members.length; i++)
  1197. {
  1198. var member = this.members[i];
  1199. if (member.untested)
  1200. {
  1201. continue;
  1202. }
  1203. if (member.type == "const")
  1204. {
  1205. test(function()
  1206. {
  1207. assert_own_property(window, this.name,
  1208. "window does not have own property " + format_value(this.name));
  1209. // "For each constant defined on an interface A, there must be
  1210. // a corresponding property on the interface object, if it
  1211. // exists."
  1212. assert_own_property(window[this.name], member.name);
  1213. // "The value of the property is that which is obtained by
  1214. // converting the constant’s IDL value to an ECMAScript
  1215. // value."
  1216. assert_equals(window[this.name][member.name], constValue(member.value),
  1217. "property has wrong value");
  1218. // "The property has attributes { [[Writable]]: false,
  1219. // [[Enumerable]]: true, [[Configurable]]: false }."
  1220. var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
  1221. assert_false("get" in desc, "property has getter");
  1222. assert_false("set" in desc, "property has setter");
  1223. assert_false(desc.writable, "property is writable");
  1224. assert_true(desc.enumerable, "property is not enumerable");
  1225. assert_false(desc.configurable, "property is configurable");
  1226. }.bind(this), this.name + " interface: constant " + member.name + " on interface object");
  1227. // "In addition, a property with the same characteristics must
  1228. // exist on the interface prototype object."
  1229. test(function()
  1230. {
  1231. assert_own_property(window, this.name,
  1232. "window does not have own property " + format_value(this.name));
  1233. if (this.has_extended_attribute("Callback")) {
  1234. assert_false("prototype" in window[this.name],
  1235. this.name + ' should not have a "prototype" property');
  1236. return;
  1237. }
  1238. assert_own_property(window[this.name], "prototype",
  1239. 'interface "' + this.name + '" does not have own property "prototype"');
  1240. assert_own_property(window[this.name].prototype, member.name);
  1241. assert_equals(window[this.name].prototype[member.name], constValue(member.value),
  1242. "property has wrong value");
  1243. var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
  1244. assert_false("get" in desc, "property has getter");
  1245. assert_false("set" in desc, "property has setter");
  1246. assert_false(desc.writable, "property is writable");
  1247. assert_true(desc.enumerable, "property is not enumerable");
  1248. assert_false(desc.configurable, "property is configurable");
  1249. }.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object");
  1250. }
  1251. else if (member.type == "attribute")
  1252. {
  1253. if (member.has_extended_attribute("Unforgeable"))
  1254. {
  1255. // We do the checks in test_interface_of instead
  1256. continue;
  1257. }
  1258. test(function()
  1259. {
  1260. assert_own_property(window, this.name,
  1261. "window does not have own property " + format_value(this.name));
  1262. assert_own_property(window[this.name], "prototype",
  1263. 'interface "' + this.name + '" does not have own property "prototype"');
  1264. assert_true(member.name in window[this.name].prototype,
  1265. "The prototype object must have a property " +
  1266. format_value(member.name));
  1267. // TODO: Needs to test for LenientThis.
  1268. assert_throws(new TypeError(), function() {
  1269. window[this.name].prototype[member.name];
  1270. }.bind(this), "getting property on prototype object must throw TypeError");
  1271. do_interface_attribute_asserts(window[this.name].prototype, member);
  1272. }.bind(this), this.name + " interface: attribute " + member.name);
  1273. }
  1274. else if (member.type == "operation")
  1275. {
  1276. // TODO: Need to correctly handle multiple operations with the same
  1277. // identifier.
  1278. if (!member.name)
  1279. {
  1280. // Unnamed getter or such
  1281. continue;
  1282. }
  1283. test(function()
  1284. {
  1285. assert_own_property(window, this.name,
  1286. "window does not have own property " + format_value(this.name));
  1287. if (this.has_extended_attribute("Callback")) {
  1288. assert_false("prototype" in window[this.name],
  1289. this.name + ' should not have a "prototype" property');
  1290. return;
  1291. }
  1292. assert_own_property(window[this.name], "prototype",
  1293. 'interface "' + this.name + '" does not have own property "prototype"');
  1294. // "For each unique identifier of an operation defined on the
  1295. // interface, there must be a corresponding property on the
  1296. // interface prototype object (if it is a regular operation) or
  1297. // the interface object (if it is a static operation), unless
  1298. // the effective overload set for that identifier and operation
  1299. // and with an argument count of 0 (for the ECMAScript language
  1300. // binding) has no entries."
  1301. //
  1302. // TODO: The library doesn't seem to support static operations.
  1303. assert_own_property(window[this.name].prototype, member.name,
  1304. "interface prototype object missing non-static operation");
  1305. var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, member.name);
  1306. // "The property has attributes { [[Writable]]: true,
  1307. // [[Enumerable]]: true, [[Configurable]]: true }."
  1308. assert_false("get" in desc, "property has getter");
  1309. assert_false("set" in desc, "property has setter");
  1310. assert_true(desc.writable, "property is not writable");
  1311. assert_true(desc.enumerable, "property is not enumerable");
  1312. assert_true(desc.configurable, "property is not configurable");
  1313. // "The value of the property is a Function object whose
  1314. // behavior is as follows . . ."
  1315. assert_equals(typeof window[this.name].prototype[member.name], "function",
  1316. "property must be a function");
  1317. // "The value of the Function object’s “length” property is
  1318. // a Number determined as follows:
  1319. // ". . .
  1320. // "Return the length of the shortest argument list of the
  1321. // entries in S."
  1322. //
  1323. // TODO: Doesn't handle overloading or variadic arguments.
  1324. assert_equals(window[this.name].prototype[member.name].length,
  1325. member.arguments.filter(function(arg) {
  1326. return !arg.optional;
  1327. }).length,
  1328. "property has wrong .length");
  1329. // Make some suitable arguments
  1330. var args = member.arguments.map(function(arg) {
  1331. return create_suitable_object(arg.idlType);
  1332. });
  1333. // "Let O be a value determined as follows:
  1334. // ". . .
  1335. // "Otherwise, throw a TypeError."
  1336. // This should be hit if the operation is not static, there is
  1337. // no [ImplicitThis] attribute, and the this value is null.
  1338. //
  1339. // TODO: We currently ignore the static and [ImplicitThis]
  1340. // cases.
  1341. assert_throws(new TypeError(), function() {
  1342. window[this.name].prototype[member.name].apply(null, args);
  1343. }, "calling operation with this = null didn't throw TypeError");
  1344. // ". . . If O is not null and is also not a platform object
  1345. // that implements interface I, throw a TypeError."
  1346. //
  1347. // TODO: Test a platform object that implements some other
  1348. // interface. (Have to be sure to get inheritance right.)
  1349. assert_throws(new TypeError(), function() {
  1350. window[this.name].prototype[member.name].apply({}, args);
  1351. }, "calling operation with this = {} didn't throw TypeError");
  1352. }.bind(this), this.name + " interface: operation " + member.name +
  1353. "(" + member.arguments.map(function(m) { return m.idlType.idlType; }) +
  1354. ")");
  1355. }
  1356. // TODO: check more member types, like stringifier
  1357. }
  1358. };
  1359. //@}
  1360. IdlInterface.prototype.test_object = function(desc)
  1361. //@{
  1362. {
  1363. var obj, exception = null;
  1364. try
  1365. {
  1366. obj = eval(desc);
  1367. }
  1368. catch(e)
  1369. {
  1370. exception = e;
  1371. }
  1372. // TODO: WebIDLParser doesn't currently support named legacycallers, so I'm
  1373. // not sure what those would look like in the AST
  1374. var expected_typeof = this.members.some(function(member)
  1375. {
  1376. return member.legacycaller
  1377. || ("idlType" in member && member.idlType.legacycaller)
  1378. || ("idlType" in member && typeof member.idlType == "object"
  1379. && "idlType" in member.idlType && member.idlType.idlType == "legacycaller");
  1380. }) ? "function" : "object";
  1381. this.test_primary_interface_of(desc, obj, exception, expected_typeof);
  1382. var current_interface = this;
  1383. while (current_interface)
  1384. {
  1385. if (!(current_interface.name in this.array.members))
  1386. {
  1387. throw "Interface " + current_interface.name + " not found (inherited by " + this.name + ")";
  1388. }
  1389. if (current_interface.prevent_multiple_testing && current_interface.already_tested)
  1390. {
  1391. return;
  1392. }
  1393. current_interface.test_interface_of(desc, obj, exception, expected_typeof);
  1394. current_interface = this.array.members[current_interface.base];
  1395. }
  1396. };
  1397. //@}
  1398. IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception, expected_typeof)
  1399. //@{
  1400. {
  1401. // We can't easily test that its prototype is correct if there's no
  1402. // interface object, or the object is from a different global environment
  1403. // (not instanceof Object). TODO: test in this case that its prototype at
  1404. // least looks correct, even if we can't test that it's actually correct.
  1405. if (!this.has_extended_attribute("NoInterfaceObject")
  1406. && (typeof obj != expected_typeof || obj instanceof Object))
  1407. {
  1408. test(function()
  1409. {
  1410. assert_equals(exception, null, "Unexpected exception when evaluating object");
  1411. assert_equals(typeof obj, expected_typeof, "wrong typeof object");
  1412. assert_own_property(window, this.name,
  1413. "window does not have own property " + format_value(this.name));
  1414. assert_own_property(window[this.name], "prototype",
  1415. 'interface "' + this.name + '" does not have own property "prototype"');
  1416. // "The value of the internal [[Prototype]] property of the
  1417. // platform object is the interface prototype object of the primary
  1418. // interface from the platform object’s associated global
  1419. // environment."
  1420. assert_equals(Object.getPrototypeOf(obj),
  1421. window[this.name].prototype,
  1422. desc + "'s prototype is not " + this.name + ".prototype");
  1423. }.bind(this), this.name + " must be primary interface of " + desc);
  1424. }
  1425. // "The class string of a platform object that implements one or more
  1426. // interfaces must be the identifier of the primary interface of the
  1427. // platform object."
  1428. test(function()
  1429. {
  1430. assert_equals(exception, null, "Unexpected exception when evaluating object");
  1431. assert_equals(typeof obj, expected_typeof, "wrong typeof object");
  1432. assert_class_string(obj, this.name, "class string of " + desc);
  1433. if (!this.has_stringifier())
  1434. {
  1435. assert_equals(String(obj), "[object " + this.name + "]", "String(" + desc + ")");
  1436. }
  1437. }.bind(this), "Stringification of " + desc);
  1438. };
  1439. //@}
  1440. IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expected_typeof)
  1441. //@{
  1442. {
  1443. // TODO: Indexed and named properties, more checks on interface members
  1444. this.already_tested = true;
  1445. for (var i = 0; i < this.members.length; i++)
  1446. {
  1447. var member = this.members[i];
  1448. if (member.has_extended_attribute("Unforgeable"))
  1449. {
  1450. test(function()
  1451. {
  1452. assert_equals(exception, null, "Unexpected exception when evaluating object");
  1453. assert_equals(typeof obj, expected_typeof, "wrong typeof object");
  1454. do_interface_attribute_asserts(obj, member);
  1455. }.bind(this), this.name + " interface: " + desc + ' must have own property "' + member.name + '"');
  1456. }
  1457. else if ((member.type == "const"
  1458. || member.type == "attribute"
  1459. || member.type == "operation")
  1460. && member.name)
  1461. {
  1462. test(function()
  1463. {
  1464. assert_equals(exception, null, "Unexpected exception when evaluating object");
  1465. assert_equals(typeof obj, expected_typeof, "wrong typeof object");
  1466. assert_inherits(obj, member.name);
  1467. if (member.type == "const")
  1468. {
  1469. assert_equals(obj[member.name], constValue(member.value));
  1470. }
  1471. if (member.type == "attribute")
  1472. {
  1473. // Attributes are accessor properties, so they might
  1474. // legitimately throw an exception rather than returning
  1475. // anything.
  1476. var property, thrown = false;
  1477. try
  1478. {
  1479. property = obj[member.name];
  1480. }
  1481. catch (e)
  1482. {
  1483. thrown = true;
  1484. }
  1485. if (!thrown)
  1486. {
  1487. this.array.assert_type_is(property, member.idlType);
  1488. }
  1489. }
  1490. if (member.type == "operation")
  1491. {
  1492. assert_equals(typeof obj[member.name], "function");
  1493. }
  1494. }.bind(this), this.name + " interface: " + desc + ' must inherit property "' + member.name + '" with the proper type (' + i + ')');
  1495. }
  1496. // TODO: This is wrong if there are multiple operations with the same
  1497. // identifier.
  1498. // TODO: Test passing arguments of the wrong type.
  1499. if (member.type == "operation" && member.name && member.arguments.length)
  1500. {
  1501. test(function()
  1502. {
  1503. assert_equals(exception, null, "Unexpected exception when evaluating object");
  1504. assert_equals(typeof obj, expected_typeof, "wrong typeof object");
  1505. assert_inherits(obj, member.name);
  1506. var args = [];
  1507. for (var i = 0; i < member.arguments.length; i++)
  1508. {
  1509. if (member.arguments[i].optional)
  1510. {
  1511. break;
  1512. }
  1513. assert_throws(new TypeError(), function()
  1514. {
  1515. obj[member.name].apply(obj, args);
  1516. }.bind(this), "Called with " + i + " arguments");
  1517. args.push(create_suitable_object(member.arguments[i].idlType));
  1518. }
  1519. }.bind(this), this.name + " interface: calling " + member.name +
  1520. "(" + member.arguments.map(function(m) { return m.idlType.idlType; }) +
  1521. ") on " + desc + " with too few arguments must throw TypeError");
  1522. }
  1523. }
  1524. };
  1525. //@}
  1526. IdlInterface.prototype.has_stringifier = function()
  1527. //@{
  1528. {
  1529. if (this.members.some(function(member) { return member.stringifier; })) {
  1530. return true;
  1531. }
  1532. if (this.base &&
  1533. this.array.members[this.base].has_stringifier()) {
  1534. return true;
  1535. }
  1536. return false;
  1537. };
  1538. //@}
  1539. function do_interface_attribute_asserts(obj, member)
  1540. //@{
  1541. {
  1542. // "For each attribute defined on the interface, there must exist a
  1543. // corresponding property. If the attribute was declared with the
  1544. // [Unforgeable] extended attribute, then the property exists on every
  1545. // object that implements the interface. Otherwise, it exists on the
  1546. // interface’s interface prototype object."
  1547. //
  1548. // This is called by test_self() with the prototype as obj, and by
  1549. // test_interface_of() with the object as obj.
  1550. assert_own_property(obj, member.name);
  1551. // "The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]:
  1552. // true, [[Configurable]]: configurable }, where:
  1553. // "configurable is false if the attribute was declared with the
  1554. // [Unforgeable] extended attribute and true otherwise;
  1555. // "G is the attribute getter, defined below; and
  1556. // "S is the attribute setter, also defined below."
  1557. var desc = Object.getOwnPropertyDescriptor(obj, member.name);
  1558. assert_false("value" in desc, 'property descriptor has value but is supposed to be accessor');
  1559. assert_false("writable" in desc, 'property descriptor has "writable" field but is supposed to be accessor');
  1560. assert_true(desc.enumerable, "property is not enumerable");
  1561. if (member.has_extended_attribute("Unforgeable"))
  1562. {
  1563. assert_false(desc.configurable, "[Unforgeable] property must not be configurable");
  1564. }
  1565. else
  1566. {
  1567. assert_true(desc.configurable, "property must be configurable");
  1568. }
  1569. // "The attribute getter is a Function object whose behavior when invoked
  1570. // is as follows:
  1571. // "...
  1572. // "The value of the Function object’s “length” property is the Number
  1573. // value 0."
  1574. assert_equals(typeof desc.get, "function", "getter must be Function");
  1575. assert_equals(desc.get.length, 0, "getter length must be 0");
  1576. // TODO: Account for LenientThis
  1577. assert_throws(new TypeError(), function()
  1578. {
  1579. desc.get.call({});
  1580. }.bind(this), "calling getter on wrong object type must throw TypeError");
  1581. // TODO: Test calling setter on the interface prototype (should throw
  1582. // TypeError in most cases).
  1583. //
  1584. // "The attribute setter is undefined if the attribute is declared readonly
  1585. // and has neither a [PutForwards] nor a [Replaceable] extended attribute
  1586. // declared on it. Otherwise, it is a Function object whose behavior when
  1587. // invoked is as follows:
  1588. // "...
  1589. // "The value of the Function object’s “length” property is the Number
  1590. // value 1."
  1591. if (member.readonly
  1592. && !member.has_extended_attribute("PutForwards")
  1593. && !member.has_extended_attribute("Replaceable"))
  1594. {
  1595. assert_equals(desc.set, undefined, "setter must be undefined for readonly attributes");
  1596. }
  1597. else
  1598. {
  1599. assert_equals(typeof desc.set, "function", "setter must be function for PutForwards, Replaceable, or non-readonly attributes");
  1600. assert_equals(desc.set.length, 1, "setter length must be 1");
  1601. }
  1602. }
  1603. //@}
  1604. /// IdlInterfaceMember ///
  1605. function IdlInterfaceMember(obj)
  1606. //@{
  1607. {
  1608. /**
  1609. * obj is an object produced by the WebIDLParser.js "ifMember" production.
  1610. * We just forward all properties to this object without modification,
  1611. * except for special extAttrs handling.
  1612. */
  1613. for (var k in obj)
  1614. {
  1615. this[k] = obj[k];
  1616. }
  1617. if (!("extAttrs" in this))
  1618. {
  1619. this.extAttrs = [];
  1620. }
  1621. }
  1622. //@}
  1623. IdlInterfaceMember.prototype = Object.create(IdlObject.prototype);
  1624. /// Internal helper functions ///
  1625. function create_suitable_object(type)
  1626. //@{
  1627. {
  1628. /**
  1629. * type is an object produced by the WebIDLParser.js "type" production. We
  1630. * return a JavaScript value that matches the type, if we can figure out
  1631. * how.
  1632. */
  1633. if (type.nullable)
  1634. {
  1635. return null;
  1636. }
  1637. switch (type.idlType)
  1638. {
  1639. case "any":
  1640. case "boolean":
  1641. return true;
  1642. case "byte": case "octet": case "short": case "unsigned short":
  1643. case "long": case "unsigned long": case "long long":
  1644. case "unsigned long long": case "float": case "double":
  1645. return 7;
  1646. case "DOMString":
  1647. return "foo";
  1648. case "object":
  1649. return {a: "b"};
  1650. case "Node":
  1651. return document.createTextNode("abc");
  1652. }
  1653. return null;
  1654. }
  1655. //@}
  1656. /// IdlEnum ///
  1657. // Used for IdlArray.prototype.assert_type_is
  1658. function IdlEnum(obj)
  1659. //@{
  1660. {
  1661. /**
  1662. * obj is an object produced by the WebIDLParser.js "dictionary"
  1663. * production.
  1664. */
  1665. /** Self-explanatory. */
  1666. this.name = obj.name;
  1667. console.log("Name is " + this.name);
  1668. /** An array of values produced by the "enum" production. */
  1669. this.values = obj.values;
  1670. }
  1671. //@}
  1672. IdlEnum.prototype = Object.create(IdlObject.prototype);
  1673. IdlEnum.prototype.test = function()
  1674. //@{
  1675. {
  1676. test(function()
  1677. {
  1678. // NOTHING to test
  1679. return;
  1680. });
  1681. }
  1682. //@}
  1683. }());
  1684. // vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker: