<!DOCTYPE html> <html> <head> <title>Virtual World Framework</title> <script type="text/javascript" src="qunit.js"></script> <script type="text/javascript" src="../lib/async.js"></script> <script type="text/javascript" src="../lib/crypto.js"></script> <script type="text/javascript" src="../lib/md5.js"></script> <script type="text/javascript" src="../lib/alea.js"></script> <script type="text/javascript" src="../lib/mash.js"></script> <script type="text/javascript" src="../lib/vwf.js"></script> <script type="text/javascript" src="../lib/require.js"></script> <script type="text/javascript"> require( { baseUrl: "../lib", paths: { jquery: "jquery-1.10.2.min", }, }, [ "domReady", "utility.js", // This is the common model implementation and an example model that connects the // simulation to a WebGL scene manager. "jquery", "vwf/configuration", "vwf/kernel/model", "vwf/model/javascript", "vwf/model/object", "vwf/model/stage/log", "vwf/kernel/view", "vwf/kernel/utility", "vwf/utility", "logger", ], function( ready, testUtility ) { // Verify that prototype-based inheritance in VWF works the same way as in JavaScript. ready( function() { vwf.initialize( /* models */ [ "vwf/model/javascript", "vwf/model/object" ], /* views */ [ ] ); test( "Models", function() { equal( vwf.models.actual[0].module.id, "vwf/model/javascript", "JavaScript Model" ); equal( vwf.models.actual[1].module.id, "vwf/model/object", "Object Model" ); } ); test( "Views", function() { expect(0); } ); // Validate the fixture. test( "Property Inheritance fixture JS", function() { var fixture = createFixtureJS( "empty", "value", "accessor" ); equal( fixture.top.tag, "top", "top tag" ); ok( ! fixture.top.hasOwnProperty( "property" ) ); // "empty" type ok( ! fixture.top.hasOwnProperty( "property_" ) ); // "empty" type equal( fixture.middle.tag, "middle", "middle tag" ); ok( fixture.middle.hasOwnProperty( "property" ) ); // "value" type ok( ! fixture.middle.hasOwnProperty( "property_" ) ); // "value" type equal( fixture.bottom.tag, "bottom", "bottom tag" ); ok( fixture.bottom.hasOwnProperty( "property" ) ); // "accessor" type ok( fixture.bottom.hasOwnProperty( "property_" ) ); // "accessor" type } ); // Validate the fixture. asyncTest( "Property Inheritance fixture VWF", function() { createFixtureVWF( "empty", "value", "accessor", function( fixture, cleanup ) { equal( vwf.execute( fixture.top, "this.tag" ), "top", "top tag" ); ok( ! vwf.execute( fixture.top, "this.hasOwnProperty( 'property' )" ) ); // "empty" type // ok( ! fixture.top.hasOwnProperty( "property_" ) ); // "empty" type // TODO: vwf/model/javascript internals equal( vwf.execute( fixture.middle, "this.tag" ), "middle", "middle tag" ); ok( vwf.execute( fixture.middle, "this.hasOwnProperty( 'property' )" ) ); // "value" type // ok( ! fixture.middle.hasOwnProperty( "property_" ) ); // "value" type // TODO: vwf/model/javascript internals equal( vwf.execute( fixture.bottom, "this.tag" ), "bottom", "bottom tag" ); ok( vwf.execute( fixture.bottom, "this.hasOwnProperty( 'property' )" ) ); // "accessor" type // ok( fixture.bottom.hasOwnProperty( "property_" ) ); // "accessor" type // TODO: vwf/model/javascript internals cleanup(); start(); } ); } ); // With no prior values, gets return undefined, and sets apply directly to the top. test( "Property Inheritance JS: empty, empty, empty", function() { var fixture = createFixtureJS( "empty", "empty", "empty" ); equal( fixture.top.property, undefined, "top before" ); equal( fixture.middle.property, undefined, "middle before" ); equal( fixture.bottom.property, undefined, "bottom before" ); fixture.top.property = "UpDaTeD"; equal( fixture.top.property, "UpDaTeD", "top after" ); equal( fixture.middle.property, undefined, "middle after" ); equal( fixture.bottom.property, undefined, "bottom after" ); } ); // With no prior values, gets return undefined, and sets apply directly to the top. asyncTest( "Property Inheritance VWF: empty, empty, empty", function() { createFixtureVWF( "empty", "empty", "empty", function( fixture, cleanup ) { equal( vwf.getProperty( fixture.top, "property" ), undefined, "top before" ); equal( vwf.getProperty( fixture.middle, "property" ), undefined, "middle before" ); equal( vwf.getProperty( fixture.bottom, "property" ), undefined, "bottom before" ); vwf.setProperty( fixture.top, "property", "UpDaTeD" ); equal( vwf.getProperty( fixture.top, "property" ), "UpDaTeD", "top after" ); equal( vwf.getProperty( fixture.middle, "property" ), undefined, "middle after" ); equal( vwf.getProperty( fixture.bottom, "property" ), undefined, "bottom after" ); cleanup(); start(); } ); } ); test( "Property Inheritance JS: empty, empty, value", function() { var fixture = createFixtureJS( "empty", "empty", "value" ); equal( fixture.top.property, "bottom", "top before" ); equal( fixture.middle.property, "bottom", "middle before" ); equal( fixture.bottom.property, "bottom", "bottom before" ); fixture.top.property = "UpDaTeD"; equal( fixture.top.property, "UpDaTeD", "top after" ); equal( fixture.middle.property, "bottom", "middle after" ); equal( fixture.bottom.property, "bottom", "bottom after" ); } ); asyncTest( "Property Inheritance VWF: empty, empty, value", function() { createFixtureVWF( "empty", "empty", "value", function( fixture, cleanup ) { equal( vwf.getProperty( fixture.top, "property" ), "bottom", "top before" ); equal( vwf.getProperty( fixture.middle, "property" ), "bottom", "middle before" ); equal( vwf.getProperty( fixture.bottom, "property" ), "bottom", "bottom before" ); vwf.setProperty( fixture.top, "property", "UpDaTeD" ); equal( vwf.getProperty( fixture.top, "property" ), "UpDaTeD", "top after" ); equal( vwf.getProperty( fixture.middle, "property" ), "bottom", "middle after" ); equal( vwf.getProperty( fixture.bottom, "property" ), "bottom", "bottom after" ); cleanup(); start(); } ); } ); test( "Property Inheritance JS: empty, empty, accessor", function() { var fixture = createFixtureJS( "empty", "empty", "accessor" ); equal( fixture.top.property, "BOTTOM", "top before" ); // via accessor on bottom ok( ! fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.middle.property, "BOTTOM", "middle before" ); equal( fixture.bottom.property, "BOTTOM", "bottom before" ); fixture.top.property = "UpDaTeD"; // through accessor on bottom equal( fixture.top.property, "UPDATED", "top after" ); // via accessor on bottom using value on top ok( fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.top.property_, "updated" ); equal( fixture.middle.property, "BOTTOM", "middle after" ); equal( fixture.bottom.property, "BOTTOM", "bottom after" ); } ); asyncTest( "Property Inheritance VWF: empty, empty, accessor", function() { createFixtureVWF( "empty", "empty", "accessor", function( fixture, cleanup ) { equal( vwf.getProperty( fixture.top, "property" ), "BOTTOM", "top before" ); // via accessor on bottom // ok( ! fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), "BOTTOM", "middle before" ); equal( vwf.getProperty( fixture.bottom, "property" ), "BOTTOM", "bottom before" ); vwf.setProperty( fixture.top, "property", "UpDaTeD" ); // through accessor on bottom equal( vwf.getProperty( fixture.top, "property" ), "UPDATED", "top after" ); // ok( fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals // equal( fixture.top.property_, "updated" ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), "BOTTOM", "middle after" ); equal( vwf.getProperty( fixture.bottom, "property" ), "BOTTOM", "bottom after" ); cleanup(); start(); } ); } ); test( "Property Inheritance JS: value, empty, empty", function() { var fixture = createFixtureJS( "value", "empty", "empty" ); equal( fixture.top.property, "top", "top before" ); equal( fixture.middle.property, undefined, "middle before" ); equal( fixture.bottom.property, undefined, "bottom before" ); fixture.top.property = "UpDaTeD"; equal( fixture.top.property, "UpDaTeD", "top after" ); equal( fixture.middle.property, undefined, "middle after" ); equal( fixture.bottom.property, undefined, "bottom after" ); } ); asyncTest( "Property Inheritance VWF: value, empty, empty", function() { createFixtureVWF( "value", "empty", "empty", function( fixture, cleanup ) { equal( vwf.getProperty( fixture.top, "property" ), "top", "top before" ); equal( vwf.getProperty( fixture.middle, "property" ), undefined, "middle before" ); equal( vwf.getProperty( fixture.bottom, "property" ), undefined, "bottom before" ); vwf.setProperty( fixture.top, "property", "UpDaTeD" ); equal( vwf.getProperty( fixture.top, "property" ), "UpDaTeD", "top after" ); equal( vwf.getProperty( fixture.middle, "property" ), undefined, "middle after" ); equal( vwf.getProperty( fixture.bottom, "property" ), undefined, "bottom after" ); cleanup(); start(); } ); } ); test( "Property Inheritance JS: value, empty, value", function() { var fixture = createFixtureJS( "value", "empty", "value" ); equal( fixture.top.property, "top", "top before" ); equal( fixture.middle.property, "bottom", "middle before" ); equal( fixture.bottom.property, "bottom", "bottom before" ); fixture.top.property = "UpDaTeD"; equal( fixture.top.property, "UpDaTeD", "top after" ); equal( fixture.middle.property, "bottom", "middle after" ); equal( fixture.bottom.property, "bottom", "bottom after" ); } ); asyncTest( "Property Inheritance VWF: value, empty, value", function() { createFixtureVWF( "value", "empty", "value", function( fixture, cleanup ) { equal( vwf.getProperty( fixture.top, "property" ), "top", "top before" ); equal( vwf.getProperty( fixture.middle, "property" ), "bottom", "middle before" ); equal( vwf.getProperty( fixture.bottom, "property" ), "bottom", "bottom before" ); vwf.setProperty( fixture.top, "property", "UpDaTeD" ); equal( vwf.getProperty( fixture.top, "property" ), "UpDaTeD", "top after" ); equal( vwf.getProperty( fixture.middle, "property" ), "bottom", "middle after" ); equal( vwf.getProperty( fixture.bottom, "property" ), "bottom", "bottom after" ); cleanup(); start(); } ); } ); test( "Property Inheritance JS: value, empty, accessor", function() { var fixture = createFixtureJS( "value", "empty", "accessor" ); equal( fixture.top.property, "top", "top before" ); ok( ! fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.middle.property, "BOTTOM", "middle before" ); equal( fixture.bottom.property, "BOTTOM", "bottom before" ); fixture.top.property = "UpDaTeD"; // not using accessor on bottom equal( fixture.top.property, "UpDaTeD", "top after" ); ok( ! fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.middle.property, "BOTTOM", "middle after" ); equal( fixture.bottom.property, "BOTTOM", "bottom after" ); } ); asyncTest( "Property Inheritance VWF: value, empty, accessor", function() { createFixtureVWF( "value", "empty", "accessor", function( fixture, cleanup ) { equal( vwf.getProperty( fixture.top, "property" ), "top", "top before" ); // ok( ! fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), "BOTTOM", "middle before" ); equal( vwf.getProperty( fixture.bottom, "property" ), "BOTTOM", "bottom before" ); vwf.setProperty( fixture.top, "property", "UpDaTeD" ); // not using accessor on bottom equal( vwf.getProperty( fixture.top, "property" ), "UpDaTeD", "top after" ); // ok( ! fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), "BOTTOM", "middle after" ); equal( vwf.getProperty( fixture.bottom, "property" ), "BOTTOM", "bottom after" ); cleanup(); start(); } ); } ); test( "Property Inheritance JS: accessor, empty, empty", function() { var fixture = createFixtureJS( "accessor", "empty", "empty" ); equal( fixture.top.property, "TOP", "top before" ); // via accessor on top ok( fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.top.property_, "top" ); equal( fixture.middle.property, undefined, "middle before" ); equal( fixture.bottom.property, undefined, "bottom before" ); fixture.top.property = "UpDaTeD"; // through accessor on top equal( fixture.top.property, "UPDATED", "top after" ); // via accessor on top using value on top ok( fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.top.property_, "updated" ); equal( fixture.middle.property, undefined, "middle after" ); equal( fixture.bottom.property, undefined, "bottom after" ); } ); asyncTest( "Property Inheritance VWF: accessor, empty, empty", function() { createFixtureVWF( "accessor", "empty", "empty", function( fixture, cleanup ) { equal( vwf.getProperty( fixture.top, "property" ), "TOP", "top before" ); // via accessor on top // ok( fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals // equal( fixture.top.property_, "top" ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), undefined, "middle before" ); equal( vwf.getProperty( fixture.bottom, "property" ), undefined, "bottom before" ); vwf.setProperty( fixture.top, "property", "UpDaTeD" ); // through accessor on top equal( vwf.getProperty( fixture.top, "property" ), "UPDATED", "top after" ); // via accessor on top using value on top // ok( fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals // equal( fixture.top.property_, "updated" ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), undefined, "middle after" ); equal( vwf.getProperty( fixture.bottom, "property" ), undefined, "bottom after" ); cleanup(); start(); } ); } ); test( "Property Inheritance JS: accessor, empty, value", function() { var fixture = createFixtureJS( "accessor", "empty", "value" ); equal( fixture.top.property, "TOP", "top before" ); // via accessor on top ok( fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.top.property_, "top" ); equal( fixture.middle.property, "bottom", "middle before" ); equal( fixture.bottom.property, "bottom", "bottom before" ); fixture.top.property = "UpDaTeD"; // through accessor on top equal( fixture.top.property, "UPDATED", "top after" ); // via accessor on top using value on top ok( fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.top.property_, "updated" ); equal( fixture.middle.property, "bottom", "middle after" ); equal( fixture.bottom.property, "bottom", "bottom after" ); } ); asyncTest( "Property Inheritance VWF: accessor, empty, value", function() { createFixtureVWF( "accessor", "empty", "value", function( fixture, cleanup ) { equal( vwf.getProperty( fixture.top, "property" ), "TOP", "top before" ); // via accessor on top // ok( fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals // equal( fixture.top.property_, "top" ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), "bottom", "middle before" ); equal( vwf.getProperty( fixture.bottom, "property" ), "bottom", "bottom before" ); vwf.setProperty( fixture.top, "property", "UpDaTeD" ); // through accessor on top equal( vwf.getProperty( fixture.top, "property" ), "UPDATED", "top after" ); // via accessor on top using value on top // ok( fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals // equal( fixture.top.property_, "updated" ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), "bottom", "middle after" ); equal( vwf.getProperty( fixture.bottom, "property" ), "bottom", "bottom after" ); cleanup(); start(); } ); } ); test( "Property Inheritance JS: accessor, empty, accessor", function() { var fixture = createFixtureJS( "accessor", "empty", "accessor" ); equal( fixture.top.property, "TOP", "top before" ); // via accessor on top ok( fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.top.property_, "top" ); equal( fixture.middle.property, "BOTTOM", "middle before" ); equal( fixture.bottom.property, "BOTTOM", "bottom before" ); fixture.top.property = "UpDaTeD"; // through accessor on top equal( fixture.top.property, "UPDATED", "top after" ); // via accessor on top using value on top ok( fixture.top.hasOwnProperty( "property_" ) ); equal( fixture.top.property_, "updated" ); equal( fixture.middle.property, "BOTTOM", "middle after" ); equal( fixture.bottom.property, "BOTTOM", "bottom after" ); } ); asyncTest( "Property Inheritance VWF: accessor, empty, accessor", function() { createFixtureVWF( "accessor", "empty", "accessor", function( fixture, cleanup ) { equal( vwf.getProperty( fixture.top, "property" ), "TOP", "top before" ); // via accessor on top // ok( fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals // equal( fixture.top.property_, "top" ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), "BOTTOM", "middle before" ); equal( vwf.getProperty( fixture.bottom, "property" ), "BOTTOM", "bottom before" ); vwf.setProperty( fixture.top, "property", "UpDaTeD" ); // through accessor on top equal( vwf.getProperty( fixture.top, "property" ), "UPDATED", "top after" ); // via accessor on top using value on top // ok( fixture.top.hasOwnProperty( "property_" ) ); // TODO: vwf/model/object internals // equal( fixture.top.property_, "updated" ); // TODO: vwf/model/object internals equal( vwf.getProperty( fixture.middle, "property" ), "BOTTOM", "middle after" ); equal( vwf.getProperty( fixture.bottom, "property" ), "BOTTOM", "bottom after" ); cleanup(); start(); } ); } ); // == Helper functions ===================================================================== // Create a regular JavaScript object with three levels of inheritance using the given // constructors. Tag each level with a unique identifier. function createFixtureJS( top, middle, bottom ) { // Factories for constructor functions for the various cases. var factories = { // No "property" property. empty: function( tag ) { return function() { this.tag = tag; } }, // "property" as a simple value type. value: function( tag ) { return function() { Object.defineProperty( this, "property", { value: tag, writable: true } ); this.tag = tag; } }, // "property" with getter and setter functions. accessor: function( tag ) { return function() { Object.defineProperty( this, "property", { get: function() { return this.property_.toUpperCase() }, set: function( value ) { this.property_ = value.toLowerCase() } } ); this.property_ = tag; this.tag = tag; } }, }; // Construct the three-level inheritance pattern: top : middle : bottom. var bc = factories[bottom]( "bottom" ); // constructor var bi = new bc(); // instance var mc = factories[middle]( "middle" ); mc.prototype = bi; // constructor var mi = new mc(); // instance var tc = factories[top]( "top" ); tc.prototype = mi; // constructor var ti = new tc(); // instance // Return the instances at all three levels. return { top: ti, middle: mi, bottom: bi }; } // Create a VWF object with three levels of inheritance using the given configurations. function createFixtureVWF( top, middle, bottom, callback ) { // Factories for property initializers for the various cases. var factories = { // No "property" property. empty: function( tag ) { return undefined; }, // "property" as a simple value type. value: function( tag ) { return { property: { value: tag, create: true } }; }, // "property" with getter and setter functions. accessor: function( tag ) { return { property: { get: "return this.property && this.property.toUpperCase()", set: "this.property = value.toLowerCase()", value: tag } }; }, }; // Construct the three-level inheritance pattern: top : middle : bottom. var bottomProperties = factories[bottom]( "bottom" ); var middleProperties = factories[middle]( "middle" ); var topProperties = factories[top]( "top" ); vwf.createNode( { extends: "http://vwf.example.com/node.vwf", properties: bottomProperties }, function( bottomID ) { vwf.execute( bottomID, "this.tag = 'bottom'" ); vwf.createNode( { extends: bottomID, properties: middleProperties }, function( middleID ) { vwf.execute( middleID, "this.tag = 'middle'" ); vwf.createNode( { extends: middleID, properties: topProperties }, function( topID ) { vwf.execute( topID, "this.tag = 'top'" ); callback( { top: topID, middle: middleID, bottom: bottomID }, function() { vwf.deleteNode( topID ); vwf.deleteNode( middleID ); vwf.deleteNode( bottomID ); } ); } ); } ); } ); } } ); } ); </script> <link rel="stylesheet" type="text/css" href="qunit.css" /> </head> <body> <h1 id="qunit-header">Virtual World Framework</h1> <h2 id="qunit-banner"></h2> <div id="qunit-testrunner-toolbar"></div> <h2 id="qunit-userAgent"></h2> <ol id="qunit-tests"></ol> <div id="qunit-fixture">test markup, will be hidden</div> </body> </html>