123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956 |
- <!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",
- "jquery",
- "vwf/configuration",
- "vwf/kernel/model",
- "vwf/model/javascript",
- "vwf/model/object",
- "vwf/model/stage/log",
- "vwf/kernel/view",
- "vwf/view/document",
- "vwf/kernel/utility",
- "vwf/utility",
- "logger",
- ], function( ready, testUtility ) {
- // Test the kernel "future" interface.
- ready( function() {
- vwf.initialize(
- /* models */ [ "vwf/model/javascript", "vwf/model/object" ],
- /* views */ [ "vwf/view/document" ]
- );
- var kernel = require( "vwf/kernel/model" ).create( vwf ); // connect through the kernel's model interface
- // Time passage from future actions and the periodic interval.
- asyncTest( "Time passage", function() {
- createFixture( function( fixtureID, cleanup ) {
- // Calculate times. We need to find two system tick times and additional times between
- // the system ticks. This calculation will need to be adjusted if the single-user tick
- // interval changes.
- var interval = 10; // assumed periodic tick interval
- var timeStart = ( Math.floor( Math.round( vwf.time() * 1000 ) / interval ) *
- interval + interval ) / 1000; // next periodic tick
- var timeStop = ( Math.floor( Math.round( vwf.time() * 1000 ) / interval ) *
- interval + interval + interval ) / 1000; // the following periodic tick
- var time1 = fixed3( timeStart + 0.001 );
- var time2 = fixed3( timeStart + 0.002 );
- var time3 = fixed3( timeStart + 0.003 );
- timeStart = fixed3( timeStart );
- timeStop = fixed3( timeStop );
- // Create a function to drop tags by timestamp in this.property.
- kernel.execute( fixtureID, "this.mark = function( tag ) { " +
- "var time = this.time.toFixed(3); " +
- "this.property[time] || ( this.property[time] = [] ); " +
- "this.property[time].push( tag ); " +
- "}" );
- kernel.execute( fixtureID, "this.property = {}" );
- // Schedule the actions.
- kernel.execute( fixtureID, "", undefined, time1 ); // nothing
- kernel.execute( fixtureID, "this.mark( 'one' )", undefined, time2 ); // one thing
- kernel.execute( fixtureID, "this.mark( 'two' )", undefined, time3 ); // two things
- kernel.execute( fixtureID, "this.mark( 'three' )", undefined, time3 );
- kernel.execute( fixtureID, "", undefined, timeStop ); // nothing, exactly on the tick
- // Wait and test.
- testUtility.runFutureAssertions( function( time ) {
- vwf.execute( fixtureID, "this.mark( 'tick' )" ); // tick, just before assertions
-
- }, [
- { absolute: timeStart, assertion: function() {
- deepEqual( vwf.execute( fixtureID, "this.property" )[ timeStart ], [ "tick" ], "tick at the periodic interval" ) } },
- { absolute: time1, assertion: function() {
- deepEqual( vwf.execute( fixtureID, "this.property" )[ time1 ], [ "tick" ], "tick when a future action executes" ) } },
- { absolute: time2, assertion: function() {
- deepEqual( vwf.execute( fixtureID, "this.property" )[ time2 ], [ "tick", "one" ], "tick is before the future action" ) } },
- { absolute: time3, assertion: function() {
- deepEqual( vwf.execute( fixtureID, "this.property" )[ time3 ], [ "tick", "two", "three" ], "one tick per group of future actions" ) } },
- { absolute: timeStop, assertion: function() {
- deepEqual( vwf.execute( fixtureID, "this.property" )[ timeStop ], [ "tick" ], "one tick with the future action at the periodic interval time" ) } },
- ], cleanup );
- } );
- } );
- // Future JavaScript API
- asyncTest( "Future JavaScript", function() {
- createFixture( function( fixtureID, cleanup ) {
- vwf.setProperty( fixtureID, "property", undefined );
- var time0 = fixed3( vwf.time() );
- var time1 = fixed3( time0 + 0.011 );
- var time2 = fixed3( time0 + 0.012 );
- var time3 = fixed3( time0 + 0.013 );
- vwf.execute( fixtureID, "this.in( " + "0.011" + " ).property = 'in'" );
- vwf.execute( fixtureID, "this.at( " + time2 + " ).property = 'at'" );
- vwf.execute( fixtureID, "this.future( " + "0.013" + " ).property = 'future'" );
- testUtility.runFutureAssertions( [
- { absolute: time1, assertion: function() {
- equal( vwf.getProperty( fixtureID, "property" ), "in", "relative" ) } },
- { absolute: time2, assertion: function() {
- equal( vwf.getProperty( fixtureID, "property" ), "at", "absolute" ) } },
- { absolute: time3, assertion: function() {
- equal( vwf.getProperty( fixtureID, "property" ), "future", "relative alias" ) } },
- ], cleanup );
- } );
- } );
- // Immediate actions directly to the kernel
- asyncTest( "Immediate kernel", function() {
- createFixture( function( fixtureID, cleanup ) {
- kernel.setProperty( fixtureID, "property", "property", undefined );
- equal( vwf.getProperty( fixtureID, "property" ), "property", "immediate property" );
- kernel.callMethod( fixtureID, "method", [ "method" ], undefined );
- equal( vwf.getProperty( fixtureID, "property" ), "method", "immediate method" );
- kernel.fireEvent( fixtureID, "event", [ "event" ], undefined );
- equal( vwf.getProperty( fixtureID, "property" ), "event", "immediate event" );
- cleanup();
- start();
- } );
- } );
- // Immediate actions through JavaScript
- asyncTest( "Immediate JavaScript", function() {
- createFixture( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.property = 'property'" );
- equal( vwf.getProperty( fixtureID, "property" ), "property", "immediate property" );
- vwf.execute( fixtureID, "this.method( 'method' )" );
- equal( vwf.getProperty( fixtureID, "property" ), "method", "immediate method" );
- vwf.execute( fixtureID, "this.event( 'event' )" );
- equal( vwf.getProperty( fixtureID, "property" ), "event", "immediate event" );
- cleanup();
- start();
- } );
- } );
- // Future actions directly to the kernel
- asyncTest( "Future kernel", function() {
- createFixture( function( fixtureID, cleanup ) {
- vwf.setProperty( fixtureID, "property", undefined );
- equal( vwf.getProperty( fixtureID, "property" ), undefined, "future initialized" );
- kernel.setProperty( fixtureID, "property", "property", -0.001 );
- kernel.callMethod( fixtureID, "method", [ "method" ], -0.002 );
- kernel.fireEvent( fixtureID, "event", [ "event" ], -0.003 );
- equal( vwf.getProperty( fixtureID, "property" ), undefined, "future queued" );
- testUtility.runFutureAssertions( [
- { relative: 0.001, assertion: function() {
- equal( vwf.getProperty( fixtureID, "property" ), "property", "future property" ) } },
- { relative: 0.002, assertion: function() {
- equal( vwf.getProperty( fixtureID, "property" ), "method", "future method" ) } },
- { relative: 0.003, assertion: function() {
- equal( vwf.getProperty( fixtureID, "property" ), "event", "future event" ) } },
- ], cleanup );
- } );
- } );
- // Future actions through JavaScript
- asyncTest( "Future JavaScript", function() {
- createFixture( function( fixtureID, cleanup ) {
- vwf.setProperty( fixtureID, "property", undefined );
- equal( vwf.getProperty( fixtureID, "property" ), undefined, "future initialized" );
- vwf.execute( fixtureID, "this.future( 0.001 ).property = 'property'" );
- vwf.execute( fixtureID, "this.future( 0.002 ).method( 'method' )" );
- vwf.execute( fixtureID, "this.future( 0.003 ).event( 'event' )" );
- equal( vwf.getProperty( fixtureID, "property" ), undefined, "future queued" );
- testUtility.runFutureAssertions( [
- { relative: 0.001, assertion: function() {
- equal( vwf.getProperty( fixtureID, "property" ), "property", "future property" ) } },
- { relative: 0.002, assertion: function() {
- equal( vwf.getProperty( fixtureID, "property" ), "method", "future method" ) } },
- { relative: 0.003, assertion: function() {
- equal( vwf.getProperty( fixtureID, "property" ), "event", "future event" ) } },
- ], cleanup );
- } );
- } );
- // Future inherited actions through JavaScript direct properties
- asyncTest( "Future JavaScript inherited direct", function() {
- createFixtureDerivedBase( function( derivedID, baseID, cleanup ) {
- equal( vwf.getProperty( derivedID, "derived" ), "derived", "derived in derived initialized" );
- equal( vwf.getProperty( derivedID, "base" ), "base", "base in derived initialized" ); // inherited
- equal( vwf.getProperty( baseID, "base" ), "base", "base in base" );
- vwf.execute( derivedID, "this.future( 0.001 ).derived = 'derived updated'" );
- vwf.execute( derivedID, "this.future( 0.002 ).base = 'base updated'" ); // inherit from base, assign to derived
-
- equal( vwf.getProperty( derivedID, "derived" ), "derived", "derived in derived queued" );
- equal( vwf.getProperty( derivedID, "base" ), "base", "base in derived queued" ); // still inherited
- equal( vwf.getProperty( baseID, "base" ), "base", "base in base unchanged" );
- testUtility.runFutureAssertions( [
- { relative: 0.001, assertion: function() {
- equal( vwf.getProperty( derivedID, "derived" ), "derived updated", "derived in derived executed" ) } },
- { relative: 0.002, assertion: function() {
- equal( vwf.getProperty( derivedID, "base" ), "base updated", "base in derived executed" ) // no longer inherited
- equal( vwf.getProperty( baseID, "base" ), "base", "base in base unchanged" ) } },
- ], cleanup );
- } );
- } );
- // Future inherited actions through JavaScript collection properties
- asyncTest( "Future JavaScript inherited collection", function() {
- createFixtureDerivedBase( function( derivedID, baseID, cleanup ) {
- equal( vwf.getProperty( derivedID, "derived" ), "derived", "derived in derived initialized" );
- equal( vwf.getProperty( derivedID, "base" ), "base", "base in derived initialized" ); // inherited
- equal( vwf.getProperty( baseID, "base" ), "base", "base in base" );
- vwf.execute( derivedID, "this.future( 0.001 ).properties.derived = 'derived updated'" );
- vwf.execute( derivedID, "this.future( 0.002 ).properties.base = 'base updated'" ); // inherit from base, assign to derived
-
- equal( vwf.getProperty( derivedID, "derived" ), "derived", "derived in derived queued" );
- equal( vwf.getProperty( derivedID, "base" ), "base", "base in derived queued" ); // still inherited
- equal( vwf.getProperty( baseID, "base" ), "base", "base in base unchanged" );
- testUtility.runFutureAssertions( [
- { relative: 0.001, assertion: function() {
- equal( vwf.getProperty( derivedID, "derived" ), "derived updated", "derived in derived executed" ) } },
- { relative: 0.002, assertion: function() {
- equal( vwf.getProperty( derivedID, "base" ), "base updated", "base in derived executed" ) // no longer inherited
- equal( vwf.getProperty( baseID, "base" ), "base", "base in base unchanged" ) } },
- ], cleanup );
- } );
- } );
- // -- Interactions between reflector messages and future messages ------------------------
- // The queue is must retain a well-defined order when future actions and reflector actions
- // share the same time, even when reflector messages have not arrived at the client yet.
- //
- // For a sequence of messages having the same time:
- //
- // - New future messages are inserted after other future messages and before any
- // reflector messages.
- //
- // - New reflector messages are appended after any future messages and after any other
- // reflector messages.
- // r0( f0 ) => r0 f0
- asyncTest( "Reflector action generating a future action for the same time", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0, "f0" ] ] ], 0 );
- testUtility.runFutureAssertions( [
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "r0 executed", // at time 0
- "- f0 scheduled", // at time 0, for time 0
- "f0 executed", // at time 0
- ], "reflector action then future action" ) } },
- ], cleanup );
- } );
- } );
- // r0( f1 ) => r0 f1
- asyncTest( "Reflector action generating a future action for a later time", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0.001, "f1" ] ] ], 0 );
- testUtility.runFutureAssertions( [
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "r0 executed", // at time 0
- "- f1 scheduled", // at time 0, for time 1
- "f1 executed" // at time 1
- ], "reflector action then future action" ) } },
- ], cleanup );
- } );
- } );
- // r0( f0a, f0b ) => r0 f0a f0b
- asyncTest( "Reflector action generating multiple future actions for the same time", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0, "f0a", 0, "f0b" ] ] ], 0 );
- testUtility.runFutureAssertions( [
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "r0 executed", // at time 0
- "- f0a scheduled", // at time 0, for time 0
- "- f0b scheduled", // at time 0, for time 0
- "f0a executed", // at time 0
- "f0b executed", // at time 0
- ], "reflector action then future actions in the order of arrival" ) } },
- ], cleanup );
- } );
- } );
- // r0( f1a, f1b ) => r0 f1a f1b
- asyncTest( "Reflector action generating multiple future actions for the same later time", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0.001, "f1a", 0.001, "f1b" ] ] ], 0 );
- testUtility.runFutureAssertions( [
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "r0 executed", // at time 0
- "- f1a scheduled", // at time 0, for time 1
- "- f1b scheduled", // at time 0, for time 1
- "f1a executed", // at time 1
- "f1b executed", // at time 1
- ], "reflector action then future actions in the order of arrival" ) } },
- ], cleanup );
- } );
- } );
- // r0( f1 ) r1 ... => r0 f1 r1
- asyncTest( "Reflector action generating a future action for a later time, with a reflector " +
- "action for that same time arriving beforehand", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0.001, "f1" ] ] ], 0 );
- vwf.execute( fixtureID, "this.methods.log( '- r1 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1" ] ], -0.001 );
- testUtility.runFutureAssertions( [
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "- r1 scheduled", // at time 0, for time 1
- "r0 executed", // at time 0
- "- f1 scheduled", // at time 0, for time 1
- "f1 executed", // at time 1
- "r1 executed", // at time 1
- ], "reflector action, later future action, then bounding reflector action" ) } },
- ], cleanup );
- } );
- } );
- // r0( f1 ) ... r1 => r0 f1 r1
- asyncTest( "Reflector action generating a future action for a later time, with a reflector " +
- "action for that same time arriving afterwards", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0.001, "f1" ] ] ], 0 );
- testUtility.runFutureAssertions( [
- { relative: 0.000, assertion: function() {
- vwf.execute( fixtureID, "this.methods.log( '- r1 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1" ] ], -0.001 ) } },
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "r0 executed", // at time 0
- "- f1 scheduled", // at time 0, for time 1
- "- r1 scheduled", // at time 0+, for time 1
- "f1 executed", // at time 1
- "r1 executed", // at time 1
- ], "reflector action, later future action, then bounding reflector action" ) } },
- ], cleanup );
- } );
- } );
- // r0( f1a, f1b ) r1a r1b ... => r0 f1a f1b r1a r1b
- asyncTest( "Reflector action generating multiple future actions for the same later time, " +
- "with multiple reflector actions for that time arriving beforehand", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0.001, "f1a", 0.001, "f1b" ] ] ], 0 );
- vwf.execute( fixtureID, "this.methods.log( '- r1a scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1a" ] ], -0.001 );
- vwf.execute( fixtureID, "this.methods.log( '- r1b scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1b" ] ], -0.001 );
- testUtility.runFutureAssertions( [
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "- r1a scheduled", // at time 0, for time 1
- "- r1b scheduled", // at time 0, for time 1
- "r0 executed", // at time 0
- "- f1a scheduled", // at time 0, for time 1
- "- f1b scheduled", // at time 0, for time 1
- "f1a executed", // at time 1
- "f1b executed", // at time 1
- "r1a executed", // at time 1
- "r1b executed", // at time 1
- ], "reflector action, later future actions, then bounding reflector actions" ) } },
- ], cleanup );
- } );
- } );
- // r0( f1a, f1b ) ... r1a r1b => r0 f1a f1b r1a r1b
- asyncTest( "Reflector action generating multiple future actions for the same later time, " +
- "with multiple reflector actions for that time arriving afterwards", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0.001, "f1a", 0.001, "f1b" ] ] ], 0 );
- testUtility.runFutureAssertions( [
- { relative: 0.000, assertion: function() {
- vwf.execute( fixtureID, "this.methods.log( '- r1a scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1a" ] ], -0.001 ) } },
- { relative: 0.000, assertion: function() {
- vwf.execute( fixtureID, "this.methods.log( '- r1b scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1b" ] ], -0.001 ) } },
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "r0 executed", // at time 0
- "- f1a scheduled", // at time 0, for time 1
- "- f1b scheduled", // at time 0, for time 1
- "- r1a scheduled", // at time 0+, for time 1
- "- r1b scheduled", // at time 0+, for time 1
- "f1a executed", // at time 1
- "f1b executed", // at time 1
- "r1a executed", // at time 1
- "r1b executed", // at time 1
- ], "reflector action, later future actions, then bounding reflector actions" ) } },
- ], cleanup );
- } );
- } );
- // r0( f1 ) r1a( f1a ) r1b ... => r0 f1 r1a f1a r1b
- asyncTest( "Reflector action generating a future action for a later time, " +
- "with a reflector action for that same time generating a future action for the same time, " +
- "followed by another reflector action for that same time", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0.001, "f1" ] ] ], 0 );
- vwf.execute( fixtureID, "this.methods.log( '- r1a scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1a", [ 0, "f1a" ] ] ], -0.001 );
- vwf.execute( fixtureID, "this.methods.log( '- r1b scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1b" ] ], -0.001 );
- testUtility.runFutureAssertions( [
- { relative: 0.020, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "- r1a scheduled", // at time 0, for time 1
- "- r1b scheduled", // at time 0, for time 1
- "r0 executed", // at time 0
- "- f1 scheduled", // at time 0, for time 1
- "f1 executed", // at time 1
- "r1a executed", // at time 1
- "- f1a scheduled", // at time 1, for time 1
- "f1a executed", // at time 1
- "r1b executed", // at time 1
- ], "reflector action, future action, first bounding reflector action, " +
- "its future action, then second bounding reflector action" ) } },
- ], cleanup );
- } );
- } );
- // r0( ff1( ff1a ) ) r1 ... => r0 ff1 ff1a r1
- asyncTest( "Reflector action generating a future action for a later time, " +
- "which generates a future action for that same time, " +
- "followed by another reflector action for the same time", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- vwf.execute( fixtureID, "this.methods.log( '- r0 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r0", [ 0.001, "ff1" ] ] ], 0 );
- vwf.execute( fixtureID, "this.methods.log( '- r1 scheduled' )" );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1" ] ], -0.001 );
- testUtility.runFutureAssertions( [
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "- r0 scheduled", // at time 0, for time 0
- "- r1 scheduled", // at time 0, for time 1
- "r0 executed", // at time 0
- "- ff1 scheduled", // at time 0, for time 1
- "ff1 executed", // at time 1
- "- ff1a scheduled", // at time 1, for time 1
- "ff1a executed", // at time 1
- "r1 executed", // at time 1
- ], "reflector action, future action, its future action, then bounding reflector action" ) } },
- ], cleanup );
- } );
- } );
- // setState should remove any messages from the queue that pre-date the setState action,
- // remove messages generated while initializing nodes during the setState action, insert
- // messages from the setState incoming queue, and leave messages in place that arrived
- // after the setState message.
- asyncTest( "setState queue", function() {
- createFixtureQueue( function( fixtureID, cleanup ) {
- // Add reflector and future messages that pre-date the setState message but that would
- // execute after it at times 2 and 3, respectively. These represent the prior state of
- // the queue. setState should remove them.
- vwf.plan( fixtureID, "callMethod", "future_", [ [ "f2" ] ], -0.002 );
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r3" ] ], -0.003 );
- // Add the setState message at time 1.
- vwf.send( undefined, "setState", undefined, [ {
- // The created node generates a future message during initialize that would run at
- // time 1, immediately following the setState action. setState should remove it.
- nodes: [
- testUtility.dataURIFromDescriptor( {
- extends:
- fixtureID,
- scripts: [
- "this.initialize = function() { " +
- "Object.getPrototypeOf( this ).future( 0 ).future_( 'f1' ); " +
- "}"
- ],
- } )
- ],
- // Include a future message at time 4 and a reflector message at time 5 in the
- // incoming queue. These should be retained.
- queue: {
- time:
- vwf.time() + 0.001,
- queue: [ {
- time: vwf.time() + 0.004,
- node: fixtureID,
- action: "callMethod",
- member: "future_",
- parameters: [ [ "f4" ] ],
- origin: "future"
- }, {
- time: vwf.time() + 0.005,
- node: fixtureID,
- action: "callMethod",
- member: "reflector",
- parameters: [ [ "r5" ] ],
- origin: "reflector"
- } ]
- }
- } ], -0.001 );
- // Add a reflector message at time 1. This represents a new action that the reflector
- // sent following the setState action. It should be retained and should execute after
- // setState.
- vwf.send( fixtureID, "callMethod", "reflector", [ [ "r1" ] ], -0.001 );
- // The expected result is that setState runs and doesn't leave a trace (other than the
- // transformed system state), the following reflector action runs, then the actions
- // from the incoming queue scheduled later run.
- testUtility.runFutureAssertions( [
- { relative: 0.010, assertion: function() {
- deepEqual( vwf.getProperty( fixtureID, "log" ), [
- "r1 executed", // second reflector action at time 1
- "f4 executed", // future action from the incoming queue at time 4
- "r5 executed", // reflector action from the incoming queue at time 5
- ], "setState discarded prior actions, added incoming actions, and retained following actions" ) } },
- ], cleanup );
- } );
- } );
- // == Helper functions =====================================================================
- // Create a node with a property, a method and an event.
- function createFixture( callback /* fixtureID, cleanup */ ) {
- vwf.createChild( 0, testUtility.uniqueName( "fixture" ), {
- extends:
- "http://vwf.example.com/node.vwf",
-
- properties: {
- property: undefined,
- },
- methods: {
- method: "this.property = arguments[0]",
- },
- events: {
- event: undefined,
- },
- scripts: [
- "this.event = this.events.add( function() { this.property = arguments[0] }, this )",
- ],
- }, undefined, function( fixtureID ) {
- callback( fixtureID, function() {
- vwf.deleteNode( fixtureID );
- } );
- } );
- }
- // Create a node with two levels of inheritance and properties to manipulate.
- function createFixtureDerivedBase( callback /* derivedID, baseID, cleanup */ ) {
- vwf.createNode( {
- extends:
- "http://vwf.example.com/node.vwf",
-
- properties: {
- base: "base",
- },
- }, function( baseID ) {
- vwf.createNode( {
- extends:
- baseID,
-
- properties: {
- derived: "derived",
- },
- }, function( derivedID ) {
- callback( derivedID, baseID, function() {
- vwf.deleteNode( derivedID );
- vwf.deleteNode( baseID );
- } );
- } );
- } );
- }
- // Create a node with methods to be called as reflector and future actions that will keep
- // a log.
- function createFixtureQueue( callback /* fixtureID, cleanup */ ) {
- vwf.createChild( 0, testUtility.uniqueName( "fixture" ), {
- extends:
- "http://vwf.example.com/node.vwf",
-
- properties: {
- log: [], // log of methods called on the node
- },
- methods: {
- // A method to be called as a reflector action. Append the first parameter to the
- // log to record that this call occurred, then schedule calls to `future` for each
- // time/tag pair in the `futures` array.
- reflector: {
- parameters:
- [ "tag", "futures" ],
- body:
- "this.methods.log( tag + ' executed' ); " + // the reflector action executes
- "while ( ( futures || [] ).length ) { " +
- "var time = futures.shift(); " +
- "var tag = futures.shift(); " +
- "this.methods.log( '- ' + tag + ' scheduled' ); " + // the future action is scheduled
- "tag.match( /ff/ ) ? " +
- "this.future( time ).methods.futurefuture( tag, tag + 'a' ) : " + // special case for future to call future
- "this.future( time ).methods.future_( tag ); " +
- "}"
- },
- // A method to be called as a future action. Append the parameter to the log to
- // record that this called occurred.
- future_: {
- parameters:
- [ "tag" ],
-
- body:
- "this.methods.log( tag + ' executed' )" // the future action executes
-
- },
- // A method to be called as a future action that generates another future action.
- // Append the first parameter to the log to record that this call occurred, then
- // schedule an additional call to `future` with the second tag.
- futurefuture: {
- parameters:
- [ "tag1", "tag2" ],
-
- body:
- "this.methods.log( tag1 + ' executed' ); " + // the future action executes
- "this.methods.log( '- ' + tag2 + ' scheduled' ); " + // another future action is scheduled
- "this.future( 0 ).methods.future_( tag2 )"
-
- },
- // Append a tag to the log.
- log: {
- parameters: [ "tag" ],
- body: "this.properties.log = this.properties.log.concat( tag )"
- },
- },
- }, undefined, function( fixtureID ) {
- callback( fixtureID, function() {
- vwf.deleteNode( fixtureID );
- } );
- } );
- }
- // Convert a number to a Number object that expresses itself in 3-point fixed precision
- // when referenced in string context.
- function fixed3( number ) {
- var number3 = new Number( number );
- number3.toString = function() {
- return this.toFixed( 3 )
- }
- return number3;
- }
- } );
- } );
- </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>
|