diff --git a/core/connection.js b/core/connection.js
index 81489c570..9da7b0171 100644
--- a/core/connection.js
+++ b/core/connection.js
@@ -200,6 +200,8 @@ Blockly.Connection.prototype.checkConnection_ = function(target) {
throw 'Source connection already connected.';
case Blockly.Connection.REASON_TARGET_NULL:
throw 'Target connection is null.';
+ case Blockly.Connection.REASON_CHECKS_FAILED:
+ throw 'Connection checks failed.';
default:
throw 'Unknown connection failure: this should never happen!';
}
@@ -293,8 +295,7 @@ Blockly.Connection.prototype.connect = function(otherConnection) {
}
// Establish the connections.
- this.targetConnection = otherConnection;
- otherConnection.targetConnection = this;
+ Blockly.Connection.connectReciprocally(this, otherConnection);
// Demote the inferior block so that one is a child of the superior one.
childBlock.setParent(parentBlock);
@@ -319,6 +320,19 @@ Blockly.Connection.prototype.connect = function(otherConnection) {
}
};
+/**
+ * Update two connections to target each other.
+ * @param {Blockly.Connection} first The first connection to update.
+ * @param {Blockly.Connection} second The second conneciton to update.
+ */
+Blockly.Connection.connectReciprocally = function(first, second) {
+ if (!first || !second) {
+ throw 'Cannot connect null connections.';
+ }
+ first.targetConnection = second;
+ second.targetConnection = first;
+}
+
/**
* Does the given block have one and only one connection point that will accept
* an orphaned block?
diff --git a/tests/jsunit/connection_db_test.js b/tests/jsunit/connection_db_test.js
new file mode 100644
index 000000000..c7f897168
--- /dev/null
+++ b/tests/jsunit/connection_db_test.js
@@ -0,0 +1,95 @@
+/**
+ * @license
+ * Blockly Tests
+ *
+ * Copyright 2015 Google Inc.
+ * https://developers.google.com/blockly/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+'use strict';
+
+function verify_DB_(msg, expected, db) {
+ var equal = (expected.length == db.length);
+ if (equal) {
+ for (var x = 0; x < expected.length; x++) {
+ if (expected[x] != db[x]) {
+ equal = false;
+ break;
+ }
+ }
+ }
+ if (equal) {
+ assertTrue(msg, true);
+ } else {
+ assertEquals(msg, expected, db);
+ }
+}
+
+function test_DB_addConnection() {
+ var db = new Blockly.ConnectionDB();
+ var o2 = {y_: 2, sourceBlock_: {}};
+ db.addConnection_(o2);
+ verify_DB_('Adding connection #2', [o2], db);
+
+ var o4 = {y_: 4, sourceBlock_: {}};
+ db.addConnection_(o4);
+ verify_DB_('Adding connection #4', [o2, o4], db);
+
+ var o1 = {y_: 1, sourceBlock_: {}};
+ db.addConnection_(o1);
+ verify_DB_('Adding connection #1', [o1, o2, o4], db);
+
+ var o3a = {y_: 3, sourceBlock_: {}};
+ db.addConnection_(o3a);
+ verify_DB_('Adding connection #3a', [o1, o2, o3a, o4], db);
+
+ var o3b = {y_: 3, sourceBlock_: {}};
+ db.addConnection_(o3b);
+ verify_DB_('Adding connection #3b', [o1, o2, o3b, o3a, o4], db);
+}
+
+function test_DB_removeConnection() {
+ var db = new Blockly.ConnectionDB();
+ var o1 = {y_: 1, sourceBlock_: {}};
+ var o2 = {y_: 2, sourceBlock_: {}};
+ var o3a = {y_: 3, sourceBlock_: {}};
+ var o3b = {y_: 3, sourceBlock_: {}};
+ var o3c = {y_: 3, sourceBlock_: {}};
+ var o4 = {y_: 4, sourceBlock_: {}};
+ db.addConnection_(o1);
+ db.addConnection_(o2);
+ db.addConnection_(o3c);
+ db.addConnection_(o3b);
+ db.addConnection_(o3a);
+ db.addConnection_(o4);
+ verify_DB_('Adding connections 1-4', [o1, o2, o3a, o3b, o3c, o4], db);
+
+ db.removeConnection_(o2);
+ verify_DB_('Removing connection #2', [o1, o3a, o3b, o3c, o4], db);
+
+ db.removeConnection_(o4);
+ verify_DB_('Removing connection #4', [o1, o3a, o3b, o3c], db);
+
+ db.removeConnection_(o1);
+ verify_DB_('Removing connection #1', [o3a, o3b, o3c], db);
+
+ db.removeConnection_(o3a);
+ verify_DB_('Removing connection #3a', [o3b, o3c], db);
+
+ db.removeConnection_(o3c);
+ verify_DB_('Removing connection #3c', [o3b], db);
+
+ db.removeConnection_(o3b);
+ verify_DB_('Removing connection #3b', [], db);
+}
diff --git a/tests/jsunit/connection_test.js b/tests/jsunit/connection_test.js
index c7f897168..b9bcc2b23 100644
--- a/tests/jsunit/connection_test.js
+++ b/tests/jsunit/connection_test.js
@@ -2,7 +2,7 @@
* @license
* Blockly Tests
*
- * Copyright 2015 Google Inc.
+ * Copyright 2016 Google Inc.
* https://developers.google.com/blockly/
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,79 +17,217 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+/**
+ * @fileoverview Tests for connection logic.
+ * @author fenichel@google.com (Rachel Fenichel)
+ */
'use strict';
-function verify_DB_(msg, expected, db) {
- var equal = (expected.length == db.length);
- if (equal) {
- for (var x = 0; x < expected.length; x++) {
- if (expected[x] != db[x]) {
- equal = false;
- break;
- }
- }
- }
- if (equal) {
- assertTrue(msg, true);
- } else {
- assertEquals(msg, expected, db);
- }
+var input;
+var output;
+var previous;
+var next;
+
+var dummyWorkspace;
+
+function connectionTest_setUp() {
+ dummyWorkspace = {};
+ input = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.INPUT_VALUE);
+ output = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.OUTPUT_VALUE);
+ previous = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.PREVIOUS_STATEMENT);
+ next = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.NEXT_STATEMENT);
}
-function test_DB_addConnection() {
- var db = new Blockly.ConnectionDB();
- var o2 = {y_: 2, sourceBlock_: {}};
- db.addConnection_(o2);
- verify_DB_('Adding connection #2', [o2], db);
-
- var o4 = {y_: 4, sourceBlock_: {}};
- db.addConnection_(o4);
- verify_DB_('Adding connection #4', [o2, o4], db);
-
- var o1 = {y_: 1, sourceBlock_: {}};
- db.addConnection_(o1);
- verify_DB_('Adding connection #1', [o1, o2, o4], db);
-
- var o3a = {y_: 3, sourceBlock_: {}};
- db.addConnection_(o3a);
- verify_DB_('Adding connection #3a', [o1, o2, o3a, o4], db);
-
- var o3b = {y_: 3, sourceBlock_: {}};
- db.addConnection_(o3b);
- verify_DB_('Adding connection #3b', [o1, o2, o3b, o3a, o4], db);
+function connectionTest_tearDown() {
+ input = null;
+ output = null;
+ previous = null;
+ next = null;
+ dummyWorkspace = null;
}
-function test_DB_removeConnection() {
- var db = new Blockly.ConnectionDB();
- var o1 = {y_: 1, sourceBlock_: {}};
- var o2 = {y_: 2, sourceBlock_: {}};
- var o3a = {y_: 3, sourceBlock_: {}};
- var o3b = {y_: 3, sourceBlock_: {}};
- var o3c = {y_: 3, sourceBlock_: {}};
- var o4 = {y_: 4, sourceBlock_: {}};
- db.addConnection_(o1);
- db.addConnection_(o2);
- db.addConnection_(o3c);
- db.addConnection_(o3b);
- db.addConnection_(o3a);
- db.addConnection_(o4);
- verify_DB_('Adding connections 1-4', [o1, o2, o3a, o3b, o3c, o4], db);
+/**
+ * These tests check that the reasons for failures to connect are consistent (internal view of
+ * error states).
+ */
+function testCanConnectWithReason_TargetNull() {
+ connectionTest_setUp();
- db.removeConnection_(o2);
- verify_DB_('Removing connection #2', [o1, o3a, o3b, o3c, o4], db);
+ assertEquals(Blockly.Connection.REASON_TARGET_NULL, input.canConnectWithReason_(null));
- db.removeConnection_(o4);
- verify_DB_('Removing connection #4', [o1, o3a, o3b, o3c], db);
-
- db.removeConnection_(o1);
- verify_DB_('Removing connection #1', [o3a, o3b, o3c], db);
-
- db.removeConnection_(o3a);
- verify_DB_('Removing connection #3a', [o3b, o3c], db);
-
- db.removeConnection_(o3c);
- verify_DB_('Removing connection #3c', [o3b], db);
-
- db.removeConnection_(o3b);
- verify_DB_('Removing connection #3b', [], db);
+ connectionTest_tearDown();
}
+
+function testCanConnectWithReason_Disconnect() {
+ connectionTest_setUp();
+
+ var tempConnection = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.OUTPUT_VALUE);
+ Blockly.Connection.connectReciprocally(input, tempConnection);
+ assertEquals(Blockly.Connection.REASON_MUST_DISCONNECT, input.canConnectWithReason_(output));
+
+ connectionTest_tearDown();
+}
+
+function testCanConnectWithReason_DifferentWorkspaces() {
+ connectionTest_setUp();
+
+ input = new Blockly.Connection({workspace: {}}, Blockly.INPUT_VALUE);
+ output = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.OUTPUT_VALUE);
+
+ assertEquals(Blockly.Connection.REASON_DIFFERENT_WORKSPACES, input.canConnectWithReason_(output));
+
+ connectionTest_tearDown();
+}
+
+
+function testCanConnectWithReason_Self() {
+ connectionTest_setUp();
+
+ var block = {type_: "test block"};
+ input.sourceBlock_ = block;
+ assertEquals(Blockly.Connection.REASON_SELF_CONNECTION, input.canConnectWithReason_(input));
+
+ connectionTest_tearDown();
+}
+
+function testCanConnectWithReason_Type() {
+ connectionTest_setUp();
+
+ assertEquals(Blockly.Connection.REASON_WRONG_TYPE, input.canConnectWithReason_(previous));
+ assertEquals(Blockly.Connection.REASON_WRONG_TYPE, input.canConnectWithReason_(next));
+
+ assertEquals(Blockly.Connection.REASON_WRONG_TYPE, output.canConnectWithReason_(previous));
+ assertEquals(Blockly.Connection.REASON_WRONG_TYPE, output.canConnectWithReason_(next));
+
+ assertEquals(Blockly.Connection.REASON_WRONG_TYPE, previous.canConnectWithReason_(input));
+ assertEquals(Blockly.Connection.REASON_WRONG_TYPE, previous.canConnectWithReason_(output));
+
+ assertEquals(Blockly.Connection.REASON_WRONG_TYPE, next.canConnectWithReason_(input));
+ assertEquals(Blockly.Connection.REASON_WRONG_TYPE, next.canConnectWithReason_(output));
+
+ connectionTest_tearDown();
+}
+
+function testCanConnectWithReason_CanConnect() {
+ connectionTest_setUp();
+
+ assertEquals(Blockly.Connection.CAN_CONNECT, previous.canConnectWithReason_(next));
+ assertEquals(Blockly.Connection.CAN_CONNECT, next.canConnectWithReason_(previous));
+ assertEquals(Blockly.Connection.CAN_CONNECT, input.canConnectWithReason_(output));
+ assertEquals(Blockly.Connection.CAN_CONNECT, output.canConnectWithReason_(input));
+
+ connectionTest_tearDown();
+}
+
+/**
+ * The next set of tests checks that exceptions are being thrown at the correct times (external
+ * view of errors).
+ */
+function testCheckConnection_Self() {
+ connectionTest_setUp();
+ var block = {type_: "test block"};
+ input.sourceBlock_ = block;
+ try {
+ input.checkConnection_(input);
+ fail();
+ } catch (e) {
+ // expected
+ }
+
+ connectionTest_tearDown();
+}
+
+function testCheckConnection_TypeInputPrev() {
+ connectionTest_setUp();
+ try {
+ input.checkConnection_(previous);
+ fail();
+ } catch (e) {
+ // expected
+ }
+
+ connectionTest_tearDown();
+}
+
+function testCheckConnection_TypeInputNext() {
+ connectionTest_setUp();
+ try {
+ input.checkConnection_(next);
+ fail();
+ } catch (e) {
+ // expected
+ }
+
+ connectionTest_tearDown();
+}
+
+function testCheckConnection_TypeOutputPrev() {
+ connectionTest_setUp();
+ try {
+ output.checkConnection_(previous);
+ fail();
+ } catch (e) {
+ // expected
+ }
+
+ connectionTest_tearDown();
+}
+
+function testCheckConnection_TypePrevInput() {
+ connectionTest_setUp();
+ try {
+ previous.checkConnection_(input);
+ fail();
+ } catch (e) {
+ // expected
+ }
+
+ connectionTest_tearDown();
+}
+
+function testCheckConnection_TypePrevOutput() {
+ connectionTest_setUp();
+ try {
+ previous.checkConnection_(output);
+ fail();
+ } catch (e) {
+ // expected
+ }
+
+ connectionTest_tearDown();
+}
+
+function testCheckConnection_TypeNextInput() {
+ connectionTest_setUp();
+ try {
+ next.checkConnection_(input);
+ fail();
+ } catch (e) {
+ // expected
+ }
+
+ connectionTest_tearDown();
+}
+
+function testCheckConnection_TypeNextOutput() {
+ connectionTest_setUp();
+ try {
+ next.checkConnection_(output);
+ fail();
+ } catch (e) {
+ // expected
+ }
+
+ connectionTest_tearDown();
+}
+
+function testCheckConnection_Okay() {
+ connectionTest_setUp();
+ previous.checkConnection_(next);
+ next.checkConnection_(previous);
+ input.checkConnection_(output);
+ output.checkConnection_(input);
+
+ connectionTest_tearDown();
+}
\ No newline at end of file
diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html
index 9c3df0ea6..48f134e89 100644
--- a/tests/jsunit/index.html
+++ b/tests/jsunit/index.html
@@ -10,6 +10,7 @@
+