TEST_F(ControllerEngineTest, scriptConnectDisconnectControlIsDisconnectedByName) { ScopedTemporaryFile script(makeTemporaryFile( "var executed = false;\n" "var connection;\n" "connectionCallback = function() { executed = true; }\n" "testConnectDisconnectControl = function() { \n" " connection = engine.connectControl('[Test]', 'potmeter', 'connectionCallback');\n" " if (typeof connection == 'undefined')\n" " throw 'Unable to Connect controller';\n" " engine.connectControl('[Test]', 'potmeter', 'connectionCallback', 1);\n" " engine.trigger('[Test]', 'potmeter');\n" " return true;\n" "};\n" "checkConnectDisconnectControl = function() {\n" " if (executed) {\n" " throw 'Callback was executed';\n" " }\n" " return executed==false;\n" "};\n")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); EXPECT_TRUE(execute("testConnectDisconnectControl")); EXPECT_TRUE(execute("checkConnectDisconnectControl")); }
TEST_F(ControllerEngineTest, scriptConnectDisconnectControlIsDisconnectedByObject) { ScopedTemporaryFile script(makeTemporaryFile( "var executed = false;\n" "var connection;\n" "testConnectDisconnectControl = function() { \n" " connection = engine.connectControl('[Test]', 'potmeter', \n" " function() { executed = true; }\n" " );\n" " if (typeof connection == 'undefined')\n" " throw 'Unable to Connect controller';\n" " engine.connectControl('[Test]', 'potmeter', connection, 1);\n" " engine.trigger('[Test]', 'potmeter');\n" " return true;\n" "};\n" "checkConnectDisconnectControl = function() {\n" " if (executed) {\n" " throw 'Callback was executed';\n" " }\n" " return executed==false;\n" "};\n")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); EXPECT_TRUE(execute("testConnectDisconnectControl")); // trigger() calls are processed via QueuedConnection. Use processEvents() // to cause Qt to deliver them. application()->processEvents(); EXPECT_TRUE(execute("checkConnectDisconnectControl")); }
TEST_F(ControllerEngineTest, connectControl_ByStringForbidDuplicateConnections) { // Test that connecting a control to a callback specified by a string // does not make duplicate connections. This behavior is inconsistent // with the behavior when specifying a callback as a function, but // this is how it has been done, so keep the behavior to ensure old scripts // do not break. auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto pass = std::make_unique<ControlObject>(ConfigKey("[Test]", "passed")); ScopedTemporaryFile script(makeTemporaryFile( "var reaction = function(value) { " " var pass = engine.getValue('[Test]', 'passed');" " engine.setValue('[Test]', 'passed', pass + 1.0); };" "engine.connectControl('[Test]', 'co', 'reaction');" "engine.connectControl('[Test]', 'co', 'reaction');" "engine.trigger('[Test]', 'co');")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); // ControlObjectScript connections are processed via QueuedConnection. Use // processEvents() to cause Qt to deliver them. application()->processEvents(); // The counter should have been incremented exactly once. EXPECT_DOUBLE_EQ(1.0, pass->get()); }
TEST_F(ControllerEngineTest, connectionObject_Disconnect) { // Test that disconnecting using the 'disconnect' method on the connection // object returned from connectControl works. auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto pass = std::make_unique<ControlObject>(ConfigKey("[Test]", "passed")); ScopedTemporaryFile script(makeTemporaryFile( "var reaction = function(value) { " " var pass = engine.getValue('[Test]', 'passed');" " engine.setValue('[Test]', 'passed', pass + 1.0); };" "var connection = engine.makeConnection('[Test]', 'co', reaction);" "connection.trigger();" "function disconnect() { " " connection.disconnect();" " engine.trigger('[Test]', 'co'); }")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); // ControlObjectScript connections are processed via QueuedConnection. Use // processEvents() to cause Qt to deliver them. application()->processEvents(); EXPECT_TRUE(execute("disconnect")); application()->processEvents(); // The counter should have been incremented exactly once. EXPECT_DOUBLE_EQ(1.0, pass->get()); }
TEST_F(ControllerEngineTest, connectionObject_reflectDisconnect) { // Test that checks if disconnecting yields the appropriate feedback auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto pass = std::make_unique<ControlObject>(ConfigKey("[Test]", "passed")); ScopedTemporaryFile script(makeTemporaryFile( "var reaction = function(success) { " " if (success) {" " var pass = engine.getValue('[Test]', 'passed');" " engine.setValue('[Test]', 'passed', pass + 1.0); " " }" "};" "var dummy_callback = function(value) {};" "var connection = engine.makeConnection('[Test]', 'co', dummy_callback);" "reaction(connection);" "reaction(connection.isConnected);" "var successful_disconnect = connection.disconnect();" "reaction(successful_disconnect);" "reaction(!connection.isConnected);" )); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); application()->processEvents(); EXPECT_DOUBLE_EQ(4.0, pass->get()); }
TEST_F(ControllerEngineTest, connectControl_toDisconnectRemovesAllConnections) { // Test that every connection to a ControlObject is disconnected // by calling engine.connectControl(..., true). Individual connections // can only be disconnected by storing the connection object returned by // engine.connectControl and calling that object's 'disconnect' method. auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto pass = std::make_unique<ControlObject>(ConfigKey("[Test]", "passed")); ScopedTemporaryFile script(makeTemporaryFile( "var reaction = function(value) { " " var pass = engine.getValue('[Test]', 'passed');" " engine.setValue('[Test]', 'passed', pass + 1.0); };" "engine.connectControl('[Test]', 'co', reaction);" "engine.connectControl('[Test]', 'co', reaction);" "engine.trigger('[Test]', 'co');" "function disconnect() { " " engine.connectControl('[Test]', 'co', reaction, 1);" " engine.trigger('[Test]', 'co'); }")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); // ControlObjectScript connections are processed via QueuedConnection. Use // processEvents() to cause Qt to deliver them. application()->processEvents(); EXPECT_TRUE(execute("disconnect")); application()->processEvents(); // The counter should have been incremented exactly twice. EXPECT_DOUBLE_EQ(2.0, pass->get()); }
TEST_F(ControllerEngineTest, connectionExecutesWithCorrectThisObject) { // Test that callback functions are executed with JavaScript's // 'this' keyword referring to the object in which the connection // was created. auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto pass = std::make_unique<ControlObject>(ConfigKey("[Test]", "passed")); ScopedTemporaryFile script(makeTemporaryFile( "var TestObject = function () {" " this.executeTheCallback = true;" " this.connection = engine.makeConnection('[Test]', 'co', function () {" " if (this.executeTheCallback) {" " engine.setValue('[Test]', 'passed', 1);" " }" " });" "};" "var someObject = new TestObject();" "someObject.connection.trigger();")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); // ControlObjectScript connections are processed via QueuedConnection. Use // processEvents() to cause Qt to deliver them. application()->processEvents(); // The counter should have been incremented exactly once. EXPECT_DOUBLE_EQ(1.0, pass->get()); }
TEST_F(ControllerEngineTest, scriptConnectDisconnectControlNamedFunction) { ScopedTemporaryFile script(makeTemporaryFile( "var executed = false;\n" "var connection;\n" "testConnectDisconnectControlCallback = function() {\n" " executed = true;\n" "};\n" "testConnectDisconnectControl = function() { \n" " connection = engine.connectControl('[Test]', 'potmeter', \n" " 'testConnectDisconnectControlCallback');\n" " engine.trigger('[Test]', 'potmeter');\n" " return true;\n" "};\n" "checkConnectDisconnectControl = function() {\n" " connection.disconnect();\n" " if (!executed) {\n" " throw 'Did Not Execute Callback';\n" " }\n" " return executed;\n" "};\n")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); EXPECT_TRUE(execute("testConnectDisconnectControl")); // trigger() calls are processed via QueuedConnection. Use processEvents() // to cause Qt to deliver them. application()->processEvents(); EXPECT_TRUE(execute("checkConnectDisconnectControl")); }
TEST_F(ControllerEngineTest, getInvalidControlObject) { ScopedTemporaryFile script(makeTemporaryFile( "getValue = function() { return engine.getValue('[Nothing]', 'nothing'); }\n")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); EXPECT_TRUE(execute("getValue")); }
TEST_F(ControllerEngineTest, scriptGetSetValue) { ScopedTemporaryFile script(makeTemporaryFile( "getSetValue = function() { var val = engine.getValue('[Channel1]', 'co'); engine.setValue('[Channel1]', 'co', val + 1); }\n")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); ScopedControl co(new ControlObject(ConfigKey("[Channel1]", "co"))); co->set(0.0); execute("getSetValue"); EXPECT_DOUBLE_EQ(co->get(), 1.0); }
TEST_F(ControllerEngineTest, trigger) { auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto pass = std::make_unique<ControlObject>(ConfigKey("[Test]", "passed")); ScopedTemporaryFile script(makeTemporaryFile( "var reaction = function(value) { " " var pass = engine.getValue('[Test]', 'passed');" " engine.setValue('[Test]', 'passed', pass + 1.0); };" "var connection = engine.connectControl('[Test]', 'co', reaction);" "engine.trigger('[Test]', 'co');")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); // ControlObjectScript connections are processed via QueuedConnection. Use // processEvents() to cause Qt to deliver them. application()->processEvents(); // The counter should have been incremented exactly once. EXPECT_DOUBLE_EQ(1.0, pass->get()); }
TEST_F(ControllerEngineTest, automaticReaction) { ScopedTemporaryFile script(makeTemporaryFile( "setUp = function() { engine.connectControl('[Channel1]','co','reaction'); }\n" "reaction = function(value) { if (value == 2.5) print('TEST PASSED: '+value);\n" "else print('TEST FAILED! TEST FAILED! TEST FAILED: '+value); " "return value; }\n")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); ScopedControl co(new ControlObject(ConfigKey("[Channel1]", "co"))); co->set(0.0); EXPECT_TRUE(execute("setUp")); // The actual test // TODO: Have the JS call a function in this test class so the test framework // can tell if it actually passed or not co->set(2.5); }
TEST_F(ControllerEngineTest, connectionObject_DisconnectByPassingToConnectControl) { // Test that passing a connection object back to engine.connectControl // removes the connection auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto pass = std::make_unique<ControlObject>(ConfigKey("[Test]", "passed")); // The connections should be removed from the ControlObject which they were // actually connected to, regardless of the group and item arguments passed // to engine.connectControl() to remove the connection. All that should matter // is that a valid ControlObject is specified. auto dummy = std::make_unique<ControlObject>(ConfigKey("[Test]", "dummy")); ScopedTemporaryFile script(makeTemporaryFile( "var reaction = function(value) { " " var pass = engine.getValue('[Test]', 'passed');" " engine.setValue('[Test]', 'passed', pass + 1.0); };" "var connection1 = engine.connectControl('[Test]', 'co', reaction);" "var connection2 = engine.connectControl('[Test]', 'co', reaction);" "function disconnectConnection1() { " " engine.connectControl('[Test]'," " 'dummy'," " connection1);" " engine.trigger('[Test]', 'co'); }" // Whether a 4th argument is passed to engine.connectControl does not matter. "function disconnectConnection2() { " " engine.connectControl('[Test]'," " 'dummy'," " connection2, true);" " engine.trigger('[Test]', 'co'); }")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); // ControlObjectScript connections are processed via QueuedConnection. Use // processEvents() to cause Qt to deliver them. application()->processEvents(); EXPECT_TRUE(execute("disconnectConnection1")); application()->processEvents(); // The counter should have been incremented once by connection2. EXPECT_DOUBLE_EQ(1.0, pass->get()); EXPECT_TRUE(execute("disconnectConnection2")); application()->processEvents(); // The counter should not have changed. EXPECT_DOUBLE_EQ(1.0, pass->get()); }
TEST_F(ControllerEngineTest, connectionObject_MakesIndependentConnection) { // Test that multiple connections can be made to the same CO with // the same callback function and that calling their 'disconnect' method // only disconnects the callback for that object. auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto counter = std::make_unique<ControlObject>(ConfigKey("[Test]", "counter")); ScopedTemporaryFile script(makeTemporaryFile( "var incrementCounterCO = function () {" " var counter = engine.getValue('[Test]', 'counter');" " engine.setValue('[Test]', 'counter', counter + 1);" "};" "var connection1 = engine.makeConnection('[Test]', 'co', incrementCounterCO);" // Make a second connection with the same ControlObject // to check that disconnecting one does not disconnect both. "var connection2 = engine.makeConnection('[Test]', 'co', incrementCounterCO);" "function changeTestCoValue() {" " var testCoValue = engine.getValue('[Test]', 'co');" " engine.setValue('[Test]', 'co', testCoValue + 1);" "}" "function disconnectConnection1() {" " connection1.disconnect();" "}" )); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); execute("changeTestCoValue"); // ControlObjectScript connections are processed via QueuedConnection. Use // processEvents() to cause Qt to deliver them. application()->processEvents(); EXPECT_EQ(2.0, counter->get()); execute("disconnectConnection1"); // Only the callback for connection1 should have disconnected; // the callback for connection2 should still be connected, so // changing the CO they were both connected to should // increment the counter once. execute("changeTestCoValue"); application()->processEvents(); EXPECT_EQ(3.0, counter->get()); }
TEST_F(ControllerEngineTest, connectControl_ByStringRedundantConnectionObjectsAreNotIndependent) { // Test that multiple connections are not allowed when passing // the callback to engine.connectControl as a function name string. // This is weird and inconsistent, but it is how it has been done, // so keep this behavior to make sure old scripts do not break. auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto counter = std::make_unique<ControlObject>(ConfigKey("[Test]", "counter")); ScopedTemporaryFile script(makeTemporaryFile( "var incrementCounterCO = function () {" " var counter = engine.getValue('[Test]', 'counter');" " engine.setValue('[Test]', 'counter', counter + 1);" "};" "var connection1 = engine.connectControl('[Test]', 'co', 'incrementCounterCO');" // Make a second connection with the same ControlObject // to check that disconnecting one does not disconnect both. "var connection2 = engine.connectControl('[Test]', 'co', 'incrementCounterCO');" "function changeTestCoValue() {" " var testCoValue = engine.getValue('[Test]', 'co');" " engine.setValue('[Test]', 'co', testCoValue + 1);" "};" "function disconnectConnection2() {" " connection2.disconnect();" "};" )); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); execute("changeTestCoValue"); // ControlObjectScript connections are processed via QueuedConnection. Use // processEvents() to cause Qt to deliver them. application()->processEvents(); EXPECT_EQ(1.0, counter->get()); execute("disconnectConnection2"); // The connection objects should refer to the same connection, // so disconnecting one should disconnect both. execute("changeTestCoValue"); application()->processEvents(); EXPECT_EQ(1.0, counter->get()); }
TEST_F(ControllerEngineTest, connectControl_ByFunctionAllowDuplicateConnections) { // Test that duplicate connections are allowed when passing callbacks as functions. auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto pass = std::make_unique<ControlObject>(ConfigKey("[Test]", "passed")); ScopedTemporaryFile script(makeTemporaryFile( "var reaction = function(value) { " " var pass = engine.getValue('[Test]', 'passed');" " engine.setValue('[Test]', 'passed', pass + 1.0); };" "engine.connectControl('[Test]', 'co', reaction);" "engine.connectControl('[Test]', 'co', reaction);" // engine.trigger() has no way to know which connection to a ControlObject // to trigger, so it should trigger all of them. "engine.trigger('[Test]', 'co');")); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); // ControlObjectScript connections are processed via QueuedConnection. Use // processEvents() to cause Qt to deliver them. application()->processEvents(); // The counter should have been incremented exactly twice. EXPECT_DOUBLE_EQ(2.0, pass->get()); }
TEST_F(ControllerEngineTest, connectionObject_trigger) { // Test that triggering using the 'trigger' method on the connection // object returned from connectControl works. auto co = std::make_unique<ControlObject>(ConfigKey("[Test]", "co")); auto counter = std::make_unique<ControlObject>(ConfigKey("[Test]", "counter")); ScopedTemporaryFile script(makeTemporaryFile( "var incrementCounterCO = function () {" " var counter = engine.getValue('[Test]', 'counter');" " engine.setValue('[Test]', 'counter', counter + 1);" "};" "var connection1 = engine.makeConnection('[Test]', 'co', incrementCounterCO);" // Make a second connection with the same ControlObject // to check that triggering a connection object only triggers that callback, // not every callback connected to its ControlObject. "var connection2 = engine.makeConnection('[Test]', 'co', incrementCounterCO);" "connection1.trigger();" )); cEngine->evaluate(script->fileName()); EXPECT_FALSE(cEngine->hasErrors(script->fileName())); // The counter should have been incremented exactly once. EXPECT_DOUBLE_EQ(1.0, counter->get()); }