--[[----------------------------------------------------------------------------

WFModelsTest.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2011 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

------------------------------------------------------------------------------]]

	-- WF.core.lua.threading
local WFIdle = require 'WFIdle'

	-- WF.core.os
local KSDate = require 'KSDate'
local WFPlatformInfo = require 'WFPlatformInfo'

	-- WF.core.reactive
local WFAsyncTestCase = require 'WFAsyncTestCase'

	-- WF.core.self_test
local WFTestModelClient = require 'WFTestModelClient'


--------------------------------------------------------------------------------

local assert = assert


--==============================================================================

local WFModelsTest = {}

--------------------------------------------------------------------------------

function WFModelsTest.testInternalStringEncode( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFModelsTest_Server.simpleValueBStringTest' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( "foo" )

end

--------------------------------------------------------------------------------

function WFModelsTest.testInternalIntegerEncode( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFModelsTest_Server.simpleValueBIntegerTest' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( 1 )

end

--------------------------------------------------------------------------------

function WFModelsTest.testInternalTableEncode( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFModelsTest_Server.simpleValueBTableTest' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( { foo = "bar" } )

end

--------------------------------------------------------------------------------

function WFModelsTest.testSimpleModelParams( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFModelsTest_Server.simpleModelParamsTest', 1, 2, 3 )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( 6 )

end

--------------------------------------------------------------------------------

local simpleEcho_valueB

function WFModelsTest.testSimpleEcho( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFModelsTest_Server.simpleTest', 'foo' )

	local valueB = model:valueB( 'baz' )

	simpleEcho_valueB = valueB

	-- valueB:ownedOnDataB( test, function( x ) debug.print( "valueB = ", x ) end )

	assert( valueB:valueNow() == 'baz' )

	local function whenB( txt ) return function( fn )
		valueB:ownedOnDataB( test, function( x )
			if x == txt then fn() end
		end )
	end end

	whenB 'foo' ( function()
		model:postEvent( 'echo', 'floon' )
	end )

	whenB 'floon' ( function()
		model:postEvent( 'echoUpper', 'bleen' )
	end )

	whenB 'BLEEN' ( function()
		valueB:close()
		model:close()
		factory:close()
		simpleEcho_valueB = nil
		test:notifyTestDidSucceed()
	end )

	test:waitForTestToFinish( 2 )

end

--------------------------------------------------------------------------------

local simpleEchoWithUpper_valueB

function WFModelsTest.testSimpleEchoWithUpper( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFModelsTest_Server.simpleTest', 'foo' )

	local submodel = model:openModel( 'toUpper' )

	local valueB = submodel:valueB( 'baz' )

	simpleEchoWithUpper_valueB = valueB

	-- valueB:ownedOnDataB( test, function( x ) debug.print( "valueB = ", x ) end )

	assert( valueB:valueNow() == 'baz' )

	local function whenB( txt ) return function( fn )
		valueB:ownedOnDataB( test, function( x )
			if x == txt then fn() end
		end )
	end end

	whenB 'FOO' ( function()
		model:postEvent( 'echo', 'bleen' )
	end )

	whenB 'BLEEN' ( function()
		valueB:close()
		model:close()
		submodel:close()
		factory:close()
		simpleEchoWithUpper_valueB = nil
		test:notifyTestDidSucceed()
	end )

	test:waitForTestToFinish( 2 )

end

--------------------------------------------------------------------------------

local submodels_testSubmodel

function WFModelsTest.testSubmodel( test )

	local WFWorkerThread = require 'WFWorkerThread'

	submodels_testSubmodel = { }

	local M = submodels_testSubmodel

	M.factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	M.model = M.factory:openModel( 'WFModelsTest_Server.counter' )

	M.valueB = M.model:valueB( '0' )

	M.submodel = M.model:openModel( 'sub', 'foo' )

	M.subvalueB = M.submodel:valueB( 'baz' )

	M.onFoo = M.subvalueB:ownedOnDataB( test, function( x )
		if x == 'foo' then
			M.submodel:postEvent( 'echo', 'bleen' )
		end
	end )

	M.onBleen = M.subvalueB:ownedOnDataB( test, function( x )

		if x == 'bleen' then

			if M.valueB:valueNow() ~= '1' then

					-- This is a bit of a stretch to depend on since it's a
					-- separate model, but we've gone back and forth on values
					-- on another model from the same factory and what we want
					-- to see is that the count went up and then came down.

				test:notifyTestDidFail()

			end

			M.submodel:close()

			M.onZero = M.valueB:ownedOnDataB( test, function( y )

				if y == "0" then
					M = nil
					submodels_testSubmodel = nil
					test:notifyTestDidSucceed()
				end

			end )

		end

	end )

	test:waitForTestToFinish( 2 )

end

--------------------------------------------------------------------------------

local submodels_testResolvedPromiseSubmodel

function WFModelsTest.testResolvedPromiseSubmodel( test )

	local WFWorkerThread = require 'WFWorkerThread'

	submodels_testResolvedPromiseSubmodel = { }

	local M = submodels_testResolvedPromiseSubmodel

	M.factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	M.model = M.factory:openModel( 'WFModelsTest_Server.counter' )

	M.valueB = M.model:valueB( '0' )

	M.submodel = M.model:openModel( 'resolvedPromise', 'foo' )

	M.subvalue = M.submodel:valueB( 'baz' )

	M.subvalue:ownedOnDoneE( test, function()

		submodels_testResolvedPromiseSubmodel = nil

		if M.subvalue:valueNow() == "foo" then
			test:notifyTestDidSucceed()
		else
			test:notifyTestDidFail()
		end

	end )

	test:waitForTestToFinish( 2 )

end

--------------------------------------------------------------------------------

local submodels_testPromiseSubmodel

function WFModelsTest.testPromiseSubmodel( test )

	local WFWorkerThread = require 'WFWorkerThread'

	submodels_testPromiseSubmodel = { }

	local M = submodels_testPromiseSubmodel

	M.factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	M.model = M.factory:openModel( 'WFModelsTest_Server.counter' )

	M.valueB = M.model:valueB( '0' )

	M.submodel = M.model:openModel( 'promise', 'foo' )

	M.subvalue = M.submodel:valueB( 'baz' )

	M.subvalue:ownedOnDoneE( test, function()

		submodels_testPromiseSubmodel = nil

		if M.subvalue:valueNow() == 'foo' then
			test:notifyTestDidSucceed()
		else
			test:notifyTestDidFail()
		end

	end )

	M.model:postEvent( 'resolvePromiseNow' )

	test:waitForTestToFinish( 2 )

end

--------------------------------------------------------------------------------

local submodels_testAdaptedEvent

function WFModelsTest.testAdaptedEvent( test )

	local WFWorkerThread = require 'WFWorkerThread'

	submodels_testAdaptedEvent = { }

	local M = submodels_testAdaptedEvent

	M.factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	M.model = M.factory:openModel( 'WFModelsTest_Server.counter | WFModelsTest_Server.adapter' )

	M.valueB = M.model:valueB( '0' )

	M.submodel = M.model:openModel( 'rawPromise' )

	M.subvalue = M.submodel:valueB( 'baz' )

	M.subvalue:ownedOnDoneE( test, function()

		submodels_testAdaptedEvent = nil

		local value = M.subvalue:valueNow()

		if value == "BLURG" then
			test:notifyTestDidSucceed()
		else
			test:notifyTestDidFail()
		end

	end )

	M.model:postEvent( 'resolvePromiseUpper', 'blurg' )

	test:waitForTestToFinish( 2 )

end

--------------------------------------------------------------------------------

--local submodels_testConstantSubmodel

--function WFModelsTest.testConstantSubmodel( test )
--
--	local WFWorkerThread = require 'WFWorkerThread'
--
--	submodels_testConstantSubmodel = { }
--
--	local M = submodels_testConstantSubmodel
--
--	M.factory = ModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )
--
--	M.model = M.factory:openModel( "WFModelsTest_Server.counter" )
--
--	M.valueB = M.model:valueB( "0" )
--
--	M.submodel = M.model:openModel( "subConstant", "foo" )
--
--	M.subvalue = M.submodel:valueB( "baz" )
--
--	debug.print( string.format( "%d,%d,%d",
--		collectgarbage( "collect" ),
--		collectgarbage( "collect" ),
--		collectgarbage( "collect" ) ) )
--
--	M.subvalue:ownedOnDoneE( test, function()
--		submodels_testConstantSubmodel = nil
--		if M.subvalue:valueNow() == "foo" then
--			test:notifyTestDidSucceed()
--		else
--			test:notifyTestDidFail()
--		end
--	end )
--
--	test:waitForTestToFinish( 2 )
--
--end

--for i = 1, 100 do
--	WFModelsTest[ string.format( "testConstantSubmodel%d", i ) ] = WFModelsTest.testConstantSubmodel
--end

--------------------------------------------------------------------------------

local actions2

function WFModelsTest.testGCClosesModel( test )

	local WFWorkerThread = require 'WFWorkerThread'

	actions2 = { }

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFModelsTest_Server.counter' )

	local valueB = model:valueB( '0' )

	local submodel = model:openModel( 'sub', 'foo' )

	model = nil

	local subvalueB = submodel:valueB( 'baz' )

	-- We attach the actions to the values, but we actually keep them alive
	-- via the actions table. We can't attach to the test because that interferes
	-- with GC.

	actions2.onFoo = subvalueB:ownedOnDataB( subvalueB, function( x )

		if x == 'foo' then

			submodel:postEvent( 'echo', 'bleen' )
			submodel = nil

			actions2.onFoo = nil

			WFIdle.doLater( function()
				collectgarbage()
				collectgarbage()
				collectgarbage()
			end )

		end

	end )

	actions2.onBleen = subvalueB:ownedOnDataB( subvalueB, function( x )

		if x == 'bleen' then

			if valueB:valueNow() ~= '1' then

					-- This is a bit of a stretch to depend on since it's a
					-- separate model, but we've gone back and forth on values
					-- on another model from the same factory and what we want
					-- to see is that the count went up and then came down.
				test:notifyTestDidFail()

			end

			subvalueB = nil

			actions2 = {}
			actions2.onZero = valueB:ownedOnDataB( valueB, function( y )

				if y == '0' then
					actions2 = nil
					test:notifyTestDidSucceed()
				end

			end )

			WFIdle.doLater( function()
				collectgarbage()
				collectgarbage()
				collectgarbage()
			end )

		end

	end )

	test:waitForTestToFinish( 2 )

end

--------------------------------------------------------------------------------

-- @mark Server side Rx support

--------------------------------------------------------------------------------

function WFModelsTest.testObservableSingleString( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.simpleStringTest' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( 'foo' )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableInteger( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.simpleIntegerTest' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( 1 )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableScalarValue( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.scalarValue' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( 'foo' )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableTable( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.simpleTableTest' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( { foo = 'bar' } )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableMultiParams( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.multiResultTest', 1, 2, 3 )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( 1, 2, 3 )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableEcho( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.echo', 'foo' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( 'foo' )

		:waitFor( function()
			model:postEvent( 'echo', 'bar' )
			return true
		end )

		:waitFor( valueB )
		:continueWhenValueMatches( 'bar' )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableObservableTable( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.simpleObservableTable' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 3 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatches( {
			var1 = 'foo',
			var2 = 'bar',
			staticString = 'const',
			staticNumber = 42,
		} )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableSingleError( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.singleError' )

	local valueB = model:valueB()

	WFAsyncTestCase( test, 1 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatchesError( ':ignore:' )
			-- TODO [scouten 2015-06-23]: This can sometimes resolve in an error
			-- which WFAsyncTestCase can't match correctly. So it suffices to
			-- prove that we hit an error state.

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableCombinedError( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.combinedError' )

	local valueB = model:valueB()

	valueB:ownedOnErrorE( test, function( err )

		if err == 'error' then
			test:notifyTestDidSucceed()
		else
			test:notifyTestDidFail()
		end

	end )

	valueB:ownedOnDataB( test, function( value )

		if value ~= nil then
			test:notifyTestDidFail( 'no value expected' )
		end

	end )

	test:waitForTestToFinish( 4 )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableNoValue( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.noValue' )

	local valueB = model:valueB()

	valueB:ownedOnDataB( test, function( value )

		if value ~= nil then
			test:notifyTestDidFail()
		end

	end )

	valueB:ownedOnDoneE( test, function()
		test:notifyTestDidSucceed()
	end )

	test:waitForTestToFinish( 2 )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableOpenStream( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.openStream' )

	local gotResult = false

	WFAsyncTestCase( test, 4 )

		:waitFor( function()

			model:postEvent( 'setData', 42 )
			return model:valueB()

		end )

		:continueWhenValueMatches( {
			closesFast = true,
			keptOpen = 42,
		} )

		:waitFor( function()

			model:postEvent( 'setData', 100 )
			return model:valueB()

		end )

		:continueWhenValueMatchesFunction( function()

			gotResult = true

			return {
				closesFast = true,
				keptOpen = 100,
					-- The previous implementation of the lua model client would
					-- have closed the model with the closure of valueB (above)
					-- However, after porting WFTestModelClient to Rx, I decided
					-- that the model should need to be explicitly closed and not
					-- just close because a single subscription to value() was
					-- disposed.
					-- Thus now the expected value of keptOpen is 100 not 42.
			}

		end )

		:waitFor( function()

			model:close()

			return true

		end )

		:continueWhenValueMatches( 'data', true )

end

--------------------------------------------------------------------------------

function WFModelsTest.testElidedObservableStream( test )

	-- Test to makes sure values that arrive in

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.openLoudElidedStream' )

	WFAsyncTestCase( test, 3 )

		:waitFor( function()

			model:postEvent( 'postSomeDataToStream' )
			return model:valueB()

		end )

		:continueWhenValueMatches( {
			streamValue = 3,
		} )

		:waitFor( function()

			model:close()
			return true

		end )

		:continueWhenValueMatches( 'data', true )

end

--------------------------------------------------------------------------------

function WFModelsTest.testLoudObservableStream( test )

	-- Test to makes sure values are not getting dropped
	-- when we configure the server-side model accordingly.

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.openLoudNonElidedStream' )

	local valueB

	WFAsyncTestCase( test, 3 )

		:waitFor( function()

			model:postEvent( 'postSomeDataToStream' )
			valueB = model:valueB()
			return valueB

		end )
		:continueWhenValueMatches( {
			streamValue = 1,
		} )

		:waitFor( function()
			return valueB
		end )
		:continueWhenValueMatches( {
			streamValue = 2,
		} )

		:waitFor( function()
			return valueB
		end )
		:continueWhenValueMatches( {
			streamValue = 3,
		} )

		:waitFor( function()

			model:close()
			return true

		end )

		:continueWhenValueMatches( 'data', true )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableAllHaveToProduceOneResult( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.allHaveToProduceOneResult' )

	local valueB = model:valueB()

	local startTime = KSDate.timeNowForAnimation()

	WFAsyncTestCase( test, 6 )

		:verbose()

		:waitFor( valueB )
		:continueWhenValueMatchesFunction( function()

			return {
				key1 = 1,
				key2 = 2,
				key3 = 3,
			}

		end )

		:waitFor( function()

			local endTime = KSDate.timeNowForAnimation()
			return ( endTime - startTime ) > 2 -- sec

		end )

		:continueWhenValueMatches( 'data', true )

end

--------------------------------------------------------------------------------

function WFModelsTest.testObservableSubModels( test )

	local WFWorkerThread = require 'WFWorkerThread'

	local factory = WFTestModelClient.makeModelFactory( WFWorkerThread( 'WFRxModelsTest_Server.lua' ) )

	local model = factory:openModel( 'WFRxModelsTest_Server.counter' )

	local submodel1, submodel2

	local valueB = model:valueB()

	WFAsyncTestCase( test, 4 )

		:waitFor( valueB )
		:continueWhenValueMatches( 0 )

		:waitFor( function()

			submodel1 = model:openModel( 'sub' )
			return submodel1:valueB()

		end )
		:continueWhenValueMatches( 1 )

		:waitFor( function()

			submodel1:postEvent( 'echo', 100 )
			return submodel1:valueB()

		end )
		:continueWhenValueMatches( 100 )

		:waitFor( function()

			submodel2 = model:openModel( 'sub' )
			return submodel2:valueB()

		end )
		:continueWhenValueMatches( 2 )

		:waitFor( function()

			return model:valueB()

		end )
		:continueWhenValueMatches( 2 )

		:waitFor( function()

			submodel1:close()
			return model:valueB()

		end )
		:continueWhenValueMatches( 1 )

		:waitFor( function()

			submodel2:close()
			return model:valueB()

		end )
		:continueWhenValueMatches( 0 )

		:waitFor( function()

			model:close()
			return true

		end )
		:continueWhenValueMatches( 'data', true )

end

--------------------------------------------------------------------------------

return WFModelsTest
