methods.html 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Virtual World Framework</title>
  5. <script type="text/javascript" src="qunit.js"></script>
  6. <script type="text/javascript" src="../lib/async.js"></script>
  7. <script type="text/javascript" src="../lib/crypto.js"></script>
  8. <script type="text/javascript" src="../lib/md5.js"></script>
  9. <script type="text/javascript" src="../lib/alea.js"></script>
  10. <script type="text/javascript" src="../lib/mash.js"></script>
  11. <script type="text/javascript" src="../lib/vwf.js"></script>
  12. <script type="text/javascript" src="../lib/require.js"></script>
  13. <script type="text/javascript">
  14. require( {
  15. baseUrl: "../lib",
  16. paths: {
  17. jquery: "jquery-1.10.2.min",
  18. },
  19. }, [
  20. "domReady",
  21. "utility.js",
  22. "vwf/utility",
  23. "vwf/configuration",
  24. "jquery",
  25. "vwf/kernel/model",
  26. "vwf/model/javascript",
  27. "vwf/model/object",
  28. "vwf/model/stage/log",
  29. "vwf/kernel/view",
  30. "vwf/kernel/utility",
  31. "logger",
  32. ], function( ready, testUtility, utility, configuration ) {
  33. // Test methods.
  34. ready( function() {
  35. vwf.initialize(
  36. /* models */ [ "vwf/model/javascript", "vwf/model/object" ],
  37. /* views */ [ ]
  38. );
  39. // Method invocation directly to the kernel
  40. asyncTest( "Method invocation kernel", function() {
  41. createFixture( function( nodeID, cleanup ) {
  42. equal( vwf.callMethod( nodeID, "empty1" ), undefined, "Empty" );
  43. equal( vwf.callMethod( nodeID, "empty2" ), undefined, "Empty, as body" );
  44. equal( vwf.callMethod( nodeID, "empty3" ), undefined, "Empty, as parameters" );
  45. equal( vwf.callMethod( nodeID, "noParameters1" ), "result", "No parameters, as text" );
  46. equal( vwf.callMethod( nodeID, "noParameters2" ), "result", "No parameters, as body" );
  47. equal( vwf.callMethod( nodeID, "noParameters3" ), "result", "No parameters, as parameters/body" );
  48. equal( vwf.callMethod( nodeID, "unnamedParameters1", [ "value" ] ), "value", "Unnamed parameters, as text" );
  49. equal( vwf.callMethod( nodeID, "unnamedParameters2", [ "value" ] ), "value", "Unnamed parameters, as body" );
  50. equal( vwf.callMethod( nodeID, "unnamedParameters3", [ "value" ] ), "value", "Unnamed parameters, as parameters/body" );
  51. equal( vwf.callMethod( nodeID, "oneParameter", [ "a" ] ), "a", "One parameter" );
  52. deepEqual( vwf.callMethod( nodeID, "twoParameters", [ "a", "b" ] ), [ "a", "extra", "b" ], "Two parameters" );
  53. cleanup();
  54. start();
  55. } );
  56. } );
  57. // Method invocation through JavaScript
  58. asyncTest( "Method invocation JavaScript", function() {
  59. createFixture( function( nodeID, cleanup ) {
  60. equal( vwf.execute( nodeID, "this.empty1()" ), undefined, "Empty" );
  61. equal( vwf.execute( nodeID, "this.empty2()" ), undefined, "Empty, as body" );
  62. equal( vwf.execute( nodeID, "this.empty3()" ), undefined, "Empty, as parameters" );
  63. equal( vwf.execute( nodeID, "this.noParameters1()" ), "result", "No parameters, as text" );
  64. equal( vwf.execute( nodeID, "this.noParameters2()" ), "result", "No parameters, as body" );
  65. equal( vwf.execute( nodeID, "this.noParameters3()" ), "result", "No parameters, as parameters/body" );
  66. equal( vwf.execute( nodeID, "this.unnamedParameters1( 'value' )" ), "value", "Unnamed parameters, as text" );
  67. equal( vwf.execute( nodeID, "this.unnamedParameters2( 'value' )" ), "value", "Unnamed parameters, as body" );
  68. equal( vwf.execute( nodeID, "this.unnamedParameters3( 'value' )" ), "value", "Unnamed parameters, as parameters/body" );
  69. equal( vwf.execute( nodeID, "this.oneParameter( 'a' )" ), "a", "One parameter" );
  70. deepEqual( vwf.execute( nodeID, "this.twoParameters( 'a', 'b' )" ), [ "a", "extra", "b" ], "Two parameters" );
  71. cleanup();
  72. start();
  73. } );
  74. } );
  75. // Method inheritance directly to the kernel
  76. asyncTest( "Method inheritance kernel", function() {
  77. createFixtureDerivedBase( function( derivedID, baseID, cleanup ) {
  78. equal( vwf.callMethod( derivedID, "derived" ), "derived-" + derivedID, "derived method in derived" );
  79. equal( vwf.callMethod( derivedID, "base" ), "base-" + derivedID, "base method invoked on derived" );
  80. equal( vwf.callMethod( baseID, "derived" ), undefined, "derived method not visible in base" );
  81. equal( vwf.callMethod( baseID, "base" ), "base-" + baseID, "base method in base" );
  82. cleanup();
  83. start();
  84. } );
  85. } );
  86. // Method inheritance through JavaScript direct properties
  87. asyncTest( "Method inheritance JavaScript direct", function() {
  88. createFixtureDerivedBase( function( derivedID, baseID, cleanup ) {
  89. equal( vwf.execute( derivedID, "this.derived()" ), "derived-" + derivedID, "derived method in derived" );
  90. equal( vwf.execute( derivedID, "this.base()" ), "base-" + derivedID, "base method invoked on derived" );
  91. equal( vwf.execute( baseID, "this.derived && this.derived()" ), undefined, "derived method not visible in base" );
  92. equal( vwf.execute( baseID, "this.base()" ), "base-" + baseID, "base method in base" );
  93. cleanup();
  94. start();
  95. } );
  96. } );
  97. // Method inheritance through JavaScript collection properties
  98. asyncTest( "Method inheritance JavaScript collection", function() {
  99. createFixtureDerivedBase( function( derivedID, baseID, cleanup ) {
  100. equal( vwf.execute( derivedID, "this.methods.derived()" ), "derived-" + derivedID, "derived method in derived" );
  101. equal( vwf.execute( derivedID, "this.methods.base()" ), "base-" + derivedID, "base method invoked on derived" );
  102. equal( vwf.execute( baseID, "this.methods.derived && this.methods.derived()" ), undefined, "derived method not visible in base" );
  103. equal( vwf.execute( baseID, "this.methods.base()" ), "base-" + baseID, "base method in base" );
  104. cleanup();
  105. start();
  106. } );
  107. } );
  108. // Method gets
  109. asyncTest( "Method gets", function() {
  110. createFixture( function( nodeID, cleanup ) {
  111. deepEqual( vwf.getMethod( nodeID, "unhandled" ), unhandledDescriptor, "Null, unhandled" );
  112. deepEqual( vwf.getMethod( nodeID, "empty1" ), emptyDescriptor, "Empty, as text" );
  113. deepEqual( vwf.getMethod( nodeID, "empty2" ), emptyDescriptor, "Empty, as body" );
  114. deepEqual( vwf.getMethod( nodeID, "empty3" ), emptyDescriptor, "Empty, as parameters" );
  115. deepEqual( vwf.getMethod( nodeID, "noParameters1" ), noParametersDescriptor, "No parameters, as text" );
  116. deepEqual( vwf.getMethod( nodeID, "noParameters2" ), noParametersDescriptor, "No parameters, as body" );
  117. deepEqual( vwf.getMethod( nodeID, "noParameters3" ), noParametersDescriptor, "No parameters, as parameters/body" );
  118. deepEqual( vwf.getMethod( nodeID, "unnamedParameters1" ), unnamedParametersDescriptor, "Unnamed parameters, as text" );
  119. deepEqual( vwf.getMethod( nodeID, "unnamedParameters2" ), unnamedParametersDescriptor, "Unnamed parameters, as body" );
  120. deepEqual( vwf.getMethod( nodeID, "unnamedParameters3" ), unnamedParametersDescriptor, "Unnamed parameters, as parameters/body" );
  121. deepEqual( vwf.getMethod( nodeID, "oneParameter" ), oneParameterDescriptor, "One parameter" );
  122. deepEqual( vwf.getMethod( nodeID, "twoParameters" ), twoParametersDescriptor, "Two parameters" );
  123. cleanup();
  124. start();
  125. } );
  126. } );
  127. // Method sets directly to the kernel
  128. asyncTest( "Method sets kernel", function() {
  129. createFixture( function( nodeID, cleanup ) {
  130. vwf.setMethod( nodeID, "morphable",
  131. "return 'set as string'" );
  132. deepEqual( vwf.getMethod( nodeID, "morphable" ), {
  133. body: "return 'set as string'",
  134. type: "application/javascript",
  135. }, "As string" );
  136. vwf.setMethod( nodeID, "morphable",
  137. { body: "return 'set as descriptor'" } );
  138. deepEqual( vwf.getMethod( nodeID, "morphable" ), {
  139. body: "return 'set as descriptor'",
  140. type: "application/javascript",
  141. }, "As descriptor" );
  142. vwf.setMethod( nodeID, "morphable",
  143. { body: "return 'set with type'", type: "application/javascript" } );
  144. deepEqual( vwf.getMethod( nodeID, "morphable" ), {
  145. body: "return 'set with type'",
  146. type: "application/javascript",
  147. }, "As descriptor with type" );
  148. vwf.setMethod( nodeID, "morphable",
  149. { body: "return 'set with foreign type'", type: "application/bogoscript" } );
  150. deepEqual( vwf.getMethod( nodeID, "morphable" ), {
  151. body: "return 'set with foreign type'",
  152. type: "application/bogoscript",
  153. }, "As descriptor with foreign type" );
  154. cleanup();
  155. start();
  156. } );
  157. } );
  158. // Method sets through JavaScript
  159. asyncTest( "Method sets JavaScript", function() {
  160. createFixture( function( nodeID, cleanup ) {
  161. // Save the configuration settings.
  162. var config = configuration.instance;
  163. // Direct assignment from a function object.
  164. vwf.execute( nodeID,
  165. "this.methods.morphable = function() { return 'set as function' }" );
  166. deepEqual( vwf.getMethod( nodeID, "morphable" ), {
  167. body: "return 'set as function'",
  168. type: "application/javascript",
  169. }, "As function" );
  170. // Assignment of a function with a reference to a variable in the closure.
  171. var functionClosureScript =
  172. "var closureVariable = 'in the closure'; " +
  173. "this.methods.morphable = function() { " +
  174. "try { " +
  175. "return 'set as function with a closure reference: ' + closureVariable; " +
  176. "} catch ( exception ) { " +
  177. "return 'set as function with a broken closure reference'; " +
  178. "} " +
  179. "}";
  180. // With the "preserve-script-closures" compatibility option enabled.
  181. configuration.instance = { "preserve-script-closures": true };
  182. vwf.execute( nodeID, functionClosureScript );
  183. equal( vwf.callMethod( nodeID, "morphable" ), "set as function with a closure reference: in the closure", "..." );
  184. // With the "preserve-script-closures" compatibility option disabled.
  185. configuration.instance = { "preserve-script-closures": false };
  186. vwf.execute( nodeID, functionClosureScript );
  187. equal( vwf.callMethod( nodeID, "morphable" ), "set as function with a broken closure reference", "..." );
  188. // Restore the configuration settings.
  189. configuration.instance = config;
  190. cleanup();
  191. start();
  192. } );
  193. } );
  194. // Method changes and node state
  195. var changesComponentDescriptor = {
  196. methods: {
  197. method: "return 'original'"
  198. }
  199. };
  200. var changesComponentURI =
  201. testUtility.dataURIFromDescriptor( changesComponentDescriptor );
  202. var changesMethodDescriptor = {
  203. body: "return 'original'",
  204. type: "application/javascript",
  205. };
  206. var changesMethodNewBody = "return 'changed'";
  207. var changesMethodDescriptorChanged = utility.merge( {}, changesMethodDescriptor, {
  208. body: changesMethodNewBody
  209. } );
  210. asyncTest( "Method changes in node state", function() {
  211. vwf.createNode( changesComponentURI, function( nodeID ) {
  212. deepEqual( vwf.getMethod( nodeID, "method" ), changesMethodDescriptor, "Unchanged" );
  213. vwf.setMethod( nodeID, "method", changesMethodNewBody );
  214. deepEqual( vwf.getNode( nodeID ), {
  215. patches:
  216. changesComponentURI,
  217. methods: {
  218. method: changesMethodDescriptorChanged,
  219. }
  220. }, "Method changed" );
  221. vwf.deleteNode( nodeID );
  222. start();
  223. } );
  224. } );
  225. asyncTest( "Method changes to node state", function() {
  226. vwf.createNode( changesComponentURI, function( nodeID ) {
  227. deepEqual( vwf.getMethod( nodeID, "method" ), changesMethodDescriptor, "Unchanged" );
  228. vwf.setNode( nodeID, {
  229. patches:
  230. changesComponentURI,
  231. methods: {
  232. method: changesMethodDescriptorChanged,
  233. }
  234. } );
  235. deepEqual( vwf.getMethod( nodeID, "method" ).body, changesMethodNewBody, "Method changed from node state" );
  236. vwf.deleteNode( nodeID );
  237. start();
  238. } );
  239. } );
  240. // == Helper functions =====================================================================
  241. // Create a node with methods to invoke.
  242. function createFixture( callback ) {
  243. vwf.createChild( 0, testUtility.uniqueName( "node" ), {
  244. extends:
  245. "http://vwf.example.com/node.vwf",
  246. methods: {
  247. unhandled: undefined,
  248. empty1: "",
  249. empty2: { body: "" },
  250. empty3: { parameters: [], body: "" },
  251. noParameters1: "return 'result'",
  252. noParameters2: { body: "return 'result'" },
  253. noParameters3: { parameters: [], body: "return 'result'" },
  254. unnamedParameters1: "return arguments[0]",
  255. unnamedParameters2: { body: "return arguments[0]" },
  256. unnamedParameters3: { parameters: [], body: "return arguments[0]" },
  257. oneParameter: { parameters: [ "one" ], body: "return one" },
  258. twoParameters: { parameters: [ "one", "two" ], body: "return [ one, 'extra', two ]" },
  259. morphable: undefined, // for `setMethod` tests
  260. },
  261. }, undefined, function( nodeID ) {
  262. callback( nodeID, function() {
  263. vwf.deleteNode( nodeID );
  264. } );
  265. } );
  266. }
  267. // Descriptors for the methods created in `createFixture`.
  268. var unhandledDescriptor = {};
  269. var emptyDescriptor = {
  270. body: "",
  271. type: "application/javascript",
  272. };
  273. var noParametersDescriptor = {
  274. body: "return 'result'",
  275. type: "application/javascript",
  276. };
  277. var unnamedParametersDescriptor = {
  278. body: "return arguments[0]",
  279. type: "application/javascript",
  280. };
  281. var oneParameterDescriptor = {
  282. parameters: [ "one" ],
  283. body: "return one",
  284. type: "application/javascript",
  285. };
  286. var twoParametersDescriptor = {
  287. parameters: [ "one", "two" ],
  288. body: "return [ one, 'extra', two ]",
  289. type: "application/javascript",
  290. };
  291. // Create a node with two levels of inheritance and methods to invoke.
  292. function createFixtureDerivedBase( callback ) {
  293. vwf.createNode( {
  294. extends: "http://vwf.example.com/node.vwf",
  295. methods: { base: "return 'base-' + this.id", },
  296. }, function( baseID ) {
  297. vwf.createNode( {
  298. extends: baseID,
  299. methods: { derived: "return 'derived-' + this.id", },
  300. }, function( derivedID ) {
  301. callback( derivedID, baseID, function() {
  302. vwf.deleteNode( derivedID );
  303. vwf.deleteNode( baseID );
  304. } );
  305. } );
  306. } );
  307. }
  308. } );
  309. } );
  310. </script>
  311. <link rel="stylesheet" type="text/css" href="qunit.css" />
  312. </head>
  313. <body>
  314. <h1 id="qunit-header">Virtual World Framework</h1>
  315. <h2 id="qunit-banner"></h2>
  316. <div id="qunit-testrunner-toolbar"></div>
  317. <h2 id="qunit-userAgent"></h2>
  318. <ol id="qunit-tests"></ol>
  319. <div id="qunit-fixture">test markup, will be hidden</div>
  320. </body>
  321. </html>