Merge pull request #3123 from BeksOmega/tests/Connections

Connection Tracking Pt 1: Added a bunch of connection related tests
This commit is contained in:
Rachel Fenichel
2019-09-27 16:44:16 -07:00
committed by GitHub
9 changed files with 993 additions and 1311 deletions

View File

@@ -681,8 +681,8 @@ Blockly.Connection.prototype.onCheckChanged_ = function() {
/**
* Change a connection's compatibility.
* @param {*} check Compatible value type or list of value types.
* Null if all types are compatible.
* @param {string|!Array<string>} check Compatible value type or list of value
* types. Null if all types are compatible.
* @return {!Blockly.Connection} The connection being modified
* (to allow chaining).
*/

View File

@@ -178,6 +178,9 @@ Blockly.Input.prototype.isVisible = function() {
* @package
*/
Blockly.Input.prototype.setVisible = function(visible) {
// Note: Currently there are only unit tests for block.setCollapsed()
// because this function is package. If this function goes back to being a
// public API tests (lots of tests) should be added.
var renderList = [];
if (this.visible_ == visible) {
return renderList;

View File

@@ -1,310 +0,0 @@
/**
* @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.connections_.length);
if (equal) {
for (var i = 0; i < expected.length; i++) {
if (expected[i] != db.connections_[i]) {
equal = false;
break;
}
}
}
if (equal) {
assertTrue(msg, true);
} else {
assertEquals(msg, expected, db.connections_);
}
}
function test_DB_addConnection() {
var db = new Blockly.ConnectionDB();
var o2 = {y_: 2, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
db.addConnection(o2);
verify_DB_('Adding connection #2', [o2], db);
var o4 = {y_: 4, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
db.addConnection(o4);
verify_DB_('Adding connection #4', [o2, o4], db);
var o1 = {y_: 1, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
db.addConnection(o1);
verify_DB_('Adding connection #1', [o1, o2, o4], db);
var o3a = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
db.addConnection(o3a);
verify_DB_('Adding connection #3a', [o1, o2, o3a, o4], db);
var o3b = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
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_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o2 = {y_: 2, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o3a = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o3b = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o3c = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o4 = {y_: 4, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
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);
}
function test_DB_getNeighbours() {
var db = new Blockly.ConnectionDB();
// Search an empty list.
assertEquals(helper_getNeighbours(db,
10 /* x */, 10 /* y */, 100 /* radius */).length, 0);
// Set up some connections.
for (var i = 0; i < 10; i++) {
db.addConnection(helper_createConnection(0, i,
Blockly.PREVIOUS_STATEMENT, null, true));
}
// Test block belongs at beginning.
var result = helper_getNeighbours(db, 0, 0, 4);
assertEquals(5, result.length);
for (i = 0; i < result.length; i++) {
assertNotEquals(result.indexOf(db.connections_[i]), -1); // contains
}
// Test block belongs at middle.
result = helper_getNeighbours(db, 0, 4, 2);
assertEquals(5, result.length);
for (i = 0; i < result.length; i++) {
assertNotEquals(result.indexOf(db.connections_[i + 2]), -1); // contains
}
// Test block belongs at end.
result = helper_getNeighbours(db, 0, 9, 4);
assertEquals(5, result.length);
for (i = 0; i < result.length; i++) {
assertNotEquals(result.indexOf(db.connections_[i + 5]), -1); // contains
}
// Test block has no neighbours due to being out of range in the x direction.
result = helper_getNeighbours(db, 10, 9, 4);
assertEquals(result.length, 0);
// Test block has no neighbours due to being out of range in the y direction.
result = helper_getNeighbours(db, 0, 19, 4);
assertEquals(result.length, 0);
// Test block has no neighbours due to being out of range diagonally.
result = helper_getNeighbours(db, -2, -2, 2);
assertEquals(result.length, 0);
}
function test_DB_findPositionForConnection() {
var db = new Blockly.ConnectionDB();
db.addConnection(helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT,
null, true));
db.addConnection(helper_createConnection(0, 1, Blockly.PREVIOUS_STATEMENT,
null, true));
db.addConnection(helper_createConnection(0, 2, Blockly.PREVIOUS_STATEMENT,
null, true));
db.addConnection(helper_createConnection(0, 4, Blockly.PREVIOUS_STATEMENT,
null, true));
db.addConnection(helper_createConnection(0, 5, Blockly.PREVIOUS_STATEMENT,
null, true));
assertEquals(5, db.connections_.length);
var conn = helper_createConnection(0, 3, Blockly.PREVIOUS_STATEMENT, null,
true);
assertEquals(3, db.findPositionForConnection_(conn));
}
function test_DB_findConnection() {
var db = new Blockly.ConnectionDB();
for (var i = 0; i < 10; i++) {
db.addConnection(helper_createConnection(i, 0,
Blockly.PREVIOUS_STATEMENT, null, true));
db.addConnection(helper_createConnection(0, i,
Blockly.PREVIOUS_STATEMENT, null, true));
}
var conn = helper_createConnection(3, 3, Blockly.PREVIOUS_STATEMENT, null,
true);
db.addConnection(conn);
assertEquals(conn, db.connections_[db.findConnection(conn)]);
conn = helper_createConnection(3, 3, Blockly.PREVIOUS_STATEMENT, null, true);
assertEquals(-1, db.findConnection(conn));
}
function test_DB_ordering() {
var db = new Blockly.ConnectionDB();
for (var i = 0; i < 10; i++) {
db.addConnection(helper_createConnection(0, 9 - i,
Blockly.PREVIOUS_STATEMENT), null, true);
}
for (i = 0; i < 10; i++) {
assertEquals(i, db.connections_[i].y_);
}
// quasi-random
var xCoords = [-29, -47, -77, 2, 43, 34, -59, -52, -90, -36, -91, 38, 87, -20,
60, 4, -57, 65, -37, -81, 57, 58, -96, 1, 67, -79, 34, 93, -90, -99, -62,
4, 11, -36, -51, -72, 3, -50, -24, -45, -92, -38, 37, 24, -47, -73, 79,
-20, 99, 43, -10, -87, 19, 35, -62, -36, 49, 86, -24, -47, -89, 33, -44,
25, -73, -91, 85, 6, 0, 89, -94, 36, -35, 84, -9, 96, -21, 52, 10, -95, 7,
-67, -70, 62, 9, -40, -95, -9, -94, 55, 57, -96, 55, 8, -48, -57, -87, 81,
23, 65];
var yCoords = [-81, 82, 5, 47, 30, 57, -12, 28, 38, 92, -25, -20, 23, -51, 73,
-90, 8, 28, -51, -15, 81, -60, -6, -16, 77, -62, -42, -24, 35, 95, -46,
-7, 61, -16, 14, 91, 57, -38, 27, -39, 92, 47, -98, 11, -33, -72, 64, 38,
-64, -88, -35, -59, -76, -94, 45, -25, -100, -95, 63, -97, 45, 98, 99, 34,
27, 52, -18, -45, 66, -32, -38, 70, -73, -23, 5, -2, -13, -9, 48, 74, -97,
-11, 35, -79, -16, -77, 83, -57, -53, 35, -44, 100, -27, -15, 5, 39, 33,
-19, -20, -95];
for (i = 0; i < xCoords.length; i++) {
db.addConnection(helper_createConnection(xCoords[i], yCoords[i],
Blockly.PREVIOUS_STATEMENT), null, true);
}
for (i = 1; i < xCoords.length; i++) {
assertTrue(db.connections_[i].y_ >= db.connections_[i - 1].y_);
}
}
function test_SearchForClosest() {
var db = new Blockly.ConnectionDB();
var sharedWorkspace = {id: "Shared workspace"};
// Search an empty list.
assertEquals(null, helper_searchDB(db, 10 /* x */, 10 /* y */,
100 /* radius */));
db.addConnection(helper_createConnection(100, 0, Blockly.PREVIOUS_STATEMENT,
sharedWorkspace, true));
assertEquals(null, helper_searchDB(db, 0, 0, 5, sharedWorkspace));
db = new Blockly.ConnectionDB();
for (var i = 0; i < 10; i++) {
var tempConn = helper_createConnection(0, i, Blockly.PREVIOUS_STATEMENT,
sharedWorkspace, true);
tempConn.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
db.addConnection(tempConn);
}
// Should be at 0, 9.
var last = db.connections_[db.connections_.length - 1];
// Correct connection is last in db; many connections in radius.
assertEquals(last, helper_searchDB(db, 0, 10, 15, sharedWorkspace));
// Nothing nearby.
assertEquals(null, helper_searchDB(db, 100, 100, 3, sharedWorkspace));
// First in db, exact match.
assertEquals(db.connections_[0], helper_searchDB(db, 0, 0, 0, sharedWorkspace));
tempConn = helper_createConnection(6, 6, Blockly.PREVIOUS_STATEMENT,
sharedWorkspace, true);
tempConn.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
db.addConnection(tempConn);
tempConn = helper_createConnection(5, 5, Blockly.PREVIOUS_STATEMENT,
sharedWorkspace, true);
tempConn.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
db.addConnection(tempConn);
var result = helper_searchDB(db, 4, 6, 3, sharedWorkspace);
assertEquals(5, result.x_);
assertEquals(5, result.y_);
}
function helper_getNeighbours(db, x, y, radius) {
return db.getNeighbours(helper_createConnection(x, y, Blockly.NEXT_STATEMENT,
null, true),
radius);
}
function helper_searchDB(db, x, y, radius, shared_workspace) {
var tempConn = helper_createConnection(x, y,
Blockly.NEXT_STATEMENT, shared_workspace, true);
tempConn.sourceBlock_ = helper_makeSourceBlock(shared_workspace);
tempConn.sourceBlock_.nextConnection = tempConn;
var closest = db.searchForClosest(tempConn, radius, {x: 0, y: 0});
return closest.connection;
}
function helper_makeSourceBlock(sharedWorkspace) {
return {workspace: sharedWorkspace,
parentBlock_: null,
getParent: function() { return null; },
movable_: true,
isMovable: function() { return true; },
isShadow: function() { return false; },
isInsertionMarker: function() { return false; },
getFirstStatementConnection: function() { return null; }
};
}
function helper_createConnection(x, y, type, opt_shared_workspace,
opt_rendered) {
var workspace = opt_shared_workspace ? opt_shared_workspace : {};
if (opt_rendered) {
var conn = new Blockly.RenderedConnection({workspace: workspace}, type);
} else {
var conn = new Blockly.Connection({workspace: workspace}, type);
}
conn.x_ = x;
conn.y_ = y;
return conn;
}

View File

@@ -1,430 +0,0 @@
/**
* @license
* Blockly Tests
*
* Copyright 2016 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.
*/
/**
* @fileoverview Tests for connection logic.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
var input;
var output;
var previous;
var next;
var dummyWorkspace;
function connectionTest_setUp() {
dummyWorkspace = {};
function createDummyBlock() {
return {
workspace: dummyWorkspace,
isShadow: function() {return false;}
};
}
input = new Blockly.Connection(createDummyBlock(),
Blockly.INPUT_VALUE);
output = new Blockly.Connection(createDummyBlock(),
Blockly.OUTPUT_VALUE);
previous = new Blockly.Connection(createDummyBlock(),
Blockly.PREVIOUS_STATEMENT);
next = new Blockly.Connection(createDummyBlock(),
Blockly.NEXT_STATEMENT);
}
function connectionTest_tearDown() {
input = null;
output = null;
previous = null;
next = null;
dummyWorkspace = null;
}
var isMovableFn = function() { return true; };
/**
* These tests check that the reasons for failures to connect are consistent
* (internal view of error states).
*/
function testCanConnectWithReason_TargetNull() {
connectionTest_setUp();
assertEquals(Blockly.Connection.REASON_TARGET_NULL,
input.canConnectWithReason_(null));
connectionTest_tearDown();
}
function testCanConnectWithReason_Disconnect() {
connectionTest_setUp();
var tempConnection = new Blockly.Connection({workspace: dummyWorkspace, isMovable: isMovableFn},
Blockly.OUTPUT_VALUE);
Blockly.Connection.connectReciprocally_(input, tempConnection);
assertEquals(Blockly.Connection.CAN_CONNECT,
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 test_isConnectionAllowed_Distance() {
var sharedWorkspace = {};
// Two connections of opposite types near each other.
var one = helper_createConnection(5 /* x */, 10 /* y */,
Blockly.INPUT_VALUE, null, true);
one.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
var two = helper_createConnection(10 /* x */, 15 /* y */,
Blockly.OUTPUT_VALUE, null, true);
two.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
assertTrue(one.isConnectionAllowed(two, 20.0));
// Move connections farther apart.
two.x_ = 100;
two.y_ = 100;
assertFalse(one.isConnectionAllowed(two, 20.0));
}
function test_isConnectionAllowed_Unrendered() {
var sharedWorkspace = {};
var one = helper_createConnection(5 /* x */, 10 /* y */,
Blockly.INPUT_VALUE);
one.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
// Don't offer to connect an already connected left (male) value plug to
// an available right (female) value plug.
var two = helper_createConnection(0, 0, Blockly.OUTPUT_VALUE);
two.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
assertTrue(one.isConnectionAllowed(two));
var three = helper_createConnection(0, 0, Blockly.INPUT_VALUE);
three.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
Blockly.Connection.connectReciprocally_(two, three);
assertFalse(one.isConnectionAllowed(two));
// Don't connect two connections on the same block.
two.sourceBlock_ = one.sourceBlock_;
assertFalse(one.isConnectionAllowed(two));
}
function test_isConnectionAllowed_NoNext() {
var sharedWorkspace = {};
var one = helper_createConnection(0, 0, Blockly.NEXT_STATEMENT);
one.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
one.sourceBlock_.nextConnection = one;
var two = helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT);
two.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
assertTrue(two.isConnectionAllowed(one));
var three = helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT);
three.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
three.sourceBlock_.previousConnection = three;
Blockly.Connection.connectReciprocally_(one, three);
// A terminal block is allowed to replace another terminal block.
assertTrue(two.isConnectionAllowed(one));
}
function test_canConnectToPrevious_alreadyConnected() {
var sharedWorkspace = {};
var one = helper_createConnection(0, 0, Blockly.NEXT_STATEMENT);
one.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
one.sourceBlock_.nextConnection = one;
var two = helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT);
two.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
two.sourceBlock_.previousConnection = two;
Blockly.Connection.connectReciprocally_(one, two);
var three = helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT);
three.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
three.sourceBlock_.previousConnection = three;
// The next connection is already occupied and cannot disconnect itself
// mid-drag.
assertFalse(one.canConnectToPrevious_(three));
}
function test_canConnect_dragging() {
var sharedWorkspace = {};
var one = helper_createConnection(0, 0, Blockly.NEXT_STATEMENT);
one.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
one.sourceBlock_.nextConnection = one;
var two = helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT);
two.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
two.sourceBlock_.previousConnection = two;
Blockly.Connection.connectReciprocally_(one, two);
Blockly.draggingConnections_.push(one);
Blockly.draggingConnections_.push(two);
assertFalse(two.isConnectionAllowed(one));
assertFalse(one.isConnectionAllowed(two));
}
function test_canConnect_stackStart() {
var sharedWorkspace = {};
var block1Next = helper_createConnection(0, 0, Blockly.NEXT_STATEMENT);
var block1 = helper_makeSourceBlock(sharedWorkspace);
block1Next.sourceBlock_ = block1
block1.nextConnection = block1Next;
var block1Prev = helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT);
block1Prev.sourceBlock_ = block1;
block1.previousConnection = block1Prev
var block2Prev = helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT);
block2Prev.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
block2Prev.sourceBlock_.previousConnection = block2Prev;
Blockly.Connection.connectReciprocally_(block1Next, block2Prev);
var three = helper_createConnection(0, 0, Blockly.NEXT_STATEMENT);
three.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
three.sourceBlock_.nextConnection = three;
// Can connect at the beginning of the stack.
assertTrue(three.canConnectToPrevious_(block1Prev));
// But not in the middle of the stack.
assertFalse(three.canConnectToPrevious_(block2Prev));
}
function test_canConnect_stackStart_insertionMarker() {
var sharedWorkspace = {};
var block1Next = helper_createConnection(0, 0, Blockly.NEXT_STATEMENT);
var block1 = helper_makeSourceBlock(sharedWorkspace);
block1.isInsertionMarker = function() {
return true;
}
block1.getPreviousBlock = function() {
return false;
}
block1Next.sourceBlock_ = block1
block1.nextConnection = block1Next;
var block1Prev = helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT);
block1Prev.sourceBlock_ = block1;
block1.previousConnection = block1Prev
var block2Prev = helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT);
var block2 = helper_makeSourceBlock(sharedWorkspace);
block2Prev.sourceBlock_ = block2;
block2.previousConnection = block2Prev;
block2.getPreviousBlock = function() {
return block1;
}
Blockly.Connection.connectReciprocally_(block1Next, block2Prev);
var three = helper_createConnection(0, 0, Blockly.NEXT_STATEMENT);
three.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
three.sourceBlock_.nextConnection = three;
// Can't connect to the previous connection of an insertion marker.
assertFalse(three.isConnectionAllowed(block1Prev));
// But can connect to a previous connection that is already connected to an
// insertion marker.
assertTrue(three.isConnectionAllowed(block2Prev));
}
function testCheckConnection_Okay() {
connectionTest_setUp();
previous.checkConnection_(next);
next.checkConnection_(previous);
input.checkConnection_(output);
output.checkConnection_(input);
connectionTest_tearDown();
}

View File

@@ -18,8 +18,6 @@
<script src="test_utilities.js"></script>
<script src="block_test.js"></script>
<script src="connection_db_test.js"></script>
<script src="connection_test.js"></script>
<script src="event_test.js"></script>
<script src="extensions_test.js"></script>
<script src="generator_test.js"></script>

View File

@@ -21,14 +21,8 @@
suite('Blocks', function() {
setup(function() {
this.workspace = new Blockly.Workspace();
});
teardown(function() {
this.workspace.dispose();
});
suite('Connection Management', function() {
setup(function() {
Blockly.defineBlocksWithJsonArray([{
Blockly.defineBlocksWithJsonArray([
{
"type": "stack_block",
"message0": "",
"previousStatement": null,
@@ -44,13 +38,28 @@ suite('Blocks', function() {
}
],
"output": null
},
{
"type": "statement_block",
"message0": "%1",
"args0": [
{
"type": "input_statement",
"name": "STATEMENT"
}
],
"previousStatement": null,
"nextStatement": null
}]);
});
teardown(function() {
delete Blockly.Blocks['stack_block'];
delete Blockly.Blocks['row_block'];
});
});
teardown(function() {
this.workspace.dispose();
delete Blockly.Blocks['stack_block'];
delete Blockly.Blocks['row_block'];
delete Blockly.Blocks['statement_block'];
});
suite('Connection Management', function() {
suite('Unplug', function() {
function assertUnpluggedNoheal(blocks) {
// A has nothing connected to it.
@@ -431,6 +440,535 @@ suite('Blocks', function() {
});
});
});
suite('Connection Tracking', function() {
setup(function() {
this.workspace.dispose();
// The new rendered workspace will get disposed by the parent teardown.
this.workspace = Blockly.inject('blocklyDiv');
this.getInputs = function() {
return this.workspace
.connectionDBList[Blockly.INPUT_VALUE].connections_;
};
this.getOutputs = function() {
return this.workspace
.connectionDBList[Blockly.OUTPUT_VALUE].connections_;
};
this.getNext = function() {
return this.workspace
.connectionDBList[Blockly.NEXT_STATEMENT].connections_;
};
this.getPrevious = function() {
return this.workspace
.connectionDBList[Blockly.PREVIOUS_STATEMENT].connections_;
};
this.assertConnectionsEmpty = function() {
chai.assert.isEmpty(this.getInputs());
chai.assert.isEmpty(this.getOutputs());
chai.assert.isEmpty(this.getNext());
chai.assert.isEmpty(this.getPrevious());
};
this.clock = sinon.useFakeTimers();
});
teardown(function() {
this.clock.restore();
});
suite('Deserialization', function() {
test('Stack', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="stack_block"/>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
test('Multi-Stack', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="stack_block">' +
' <next>' +
' <block type="stack_block">' +
' <next>' +
' <block type="stack_block"/>' +
' </next>' +
' </block>' +
' </next>' +
' </block>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 3);
});
test('Collapsed Stack', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="stack_block" collapsed="true"/>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
test('Collapsed Multi-Stack', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="stack_block" collapsed="true">' +
' <next>' +
' <block type="stack_block" collapsed="true">' +
' <next>' +
' <block type="stack_block" collapsed="true"/>' +
' </next>' +
' </block>' +
' </next>' +
' </block>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 3);
});
test('Row', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="row_block"/>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 1);
});
test('Multi-Row', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block"/>' +
' </value>' +
' </block>' +
' </value>' +
' </block>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
});
test('Collapsed Row', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="row_block" collapsed="true"/>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 0);
});
test('Collapsed Multi-Row', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="row_block" collapsed="true">' +
' <value name="INPUT">' +
' <block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block"/>' +
' </value>' +
' </block>' +
' </value>' +
' </block>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 0);
});
test('Collapsed Multi-Row Middle', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block" collapsed="true">' +
' <value name="INPUT">' +
' <block type="row_block"/>' +
' </value>' +
' </block>' +
' </value>' +
' </block>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getOutputs().length, 2);
chai.assert.equal(this.getInputs().length, 1);
});
test('Statement', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="statement_block"/>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 2);
});
test('Multi-Statement', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block"/>' +
' </statement>' +
' </block>' +
' </statement>' +
' </block>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
});
test('Collapsed Statement', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="statement_block" collapsed="true"/>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
test('Collapsed Multi-Statement', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="statement_block" collapsed="true">' +
' <statement name="STATEMENT">' +
' <block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block"/>' +
' </statement>' +
' </block>' +
' </statement>' +
' </block>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
test('Collapsed Multi-Statement Middle', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
'<xml>' +
' <block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block" collapsed="true">' +
' <statement name="STATEMENT">' +
' <block type="statement_block"/>' +
' </statement>' +
' </block>' +
' </statement>' +
' </block>' +
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 2);
chai.assert.equal(this.getNext().length, 3);
});
});
suite('Programmatic Block Creation', function() {
test('Stack', function() {
var block = this.workspace.newBlock('stack_block');
this.assertConnectionsEmpty();
block.initSvg();
block.render();
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
test('Row', function() {
var block = this.workspace.newBlock('row_block');
this.assertConnectionsEmpty();
block.initSvg();
block.render();
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 1);
});
test('Statement', function() {
var block = this.workspace.newBlock('statement_block');
this.assertConnectionsEmpty();
block.initSvg();
block.render();
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 2);
});
});
suite('setCollapsed', function() {
test('Stack', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="stack_block"/>'
), this.workspace);
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
block.setCollapsed(true);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
block.setCollapsed(false);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
test('Multi-Stack', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="stack_block">' +
' <next>' +
' <block type="stack_block">' +
' <next>' +
' <block type="stack_block"/>' +
' </next>' +
' </block>' +
' </next>' +
'</block>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 3);
block.setCollapsed(true);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 3);
block.setCollapsed(false);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 3);
});
test('Row', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="row_block"/>'
), this.workspace);
this.clock.tick(1);
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 1);
block.setCollapsed(true);
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 0);
block.setCollapsed(false);
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 1);
});
test('Multi-Row', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block"/>' +
' </value>' +
' </block>' +
' </value>' +
'</block>'
), this.workspace);
this.clock.tick(1);
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
block.setCollapsed(true);
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 0);
block.setCollapsed(false);
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
});
test('Multi-Row Middle', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block"/>' +
' </value>' +
' </block>' +
' </value>' +
'</block>'
), this.workspace);
this.clock.tick(1);
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
block = block.getInputTargetBlock('INPUT');
block.setCollapsed(true);
chai.assert.equal(this.getOutputs().length, 2);
chai.assert.equal(this.getInputs().length, 1);
block.setCollapsed(false);
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
});
test('Multi-Row Double Collapse', function() {
// Collapse middle -> Collapse top ->
// Uncollapse top -> Uncollapse middle
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block">' +
' <value name="INPUT">' +
' <block type="row_block"/>' +
' </value>' +
' </block>' +
' </value>' +
'</block>'
), this.workspace);
this.clock.tick(1);
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
var middleBlock = block.getInputTargetBlock('INPUT');
middleBlock.setCollapsed(true);
chai.assert.equal(this.getOutputs().length, 2);
chai.assert.equal(this.getInputs().length, 1);
block.setCollapsed(true);
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 0);
block.setCollapsed(false);
chai.assert.equal(this.getOutputs().length, 2);
chai.assert.equal(this.getInputs().length, 1);
middleBlock.setCollapsed(false);
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
});
test('Statement', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="statement_block"/>'
), this.workspace);
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 2);
block.setCollapsed(true);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
block.setCollapsed(false);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 2);
});
test('Multi-Statement', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block"/>' +
' </statement>' +
' </block>' +
' </statement>' +
'</block>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
block.setCollapsed(true);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
block.setCollapsed(false);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
});
test('Multi-Statement Middle', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block"/>' +
' </statement>' +
' </block>' +
' </statement>' +
'</block>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
block = block.getInputTargetBlock('STATEMENT');
block.setCollapsed(true);
chai.assert.equal(this.getPrevious().length, 2);
chai.assert.equal(this.getNext().length, 3);
block.setCollapsed(false);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
});
test('Multi-Statement Double Collapse', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block"/>' +
' </statement>' +
' </block>' +
' </statement>' +
'</block>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
var middleBlock = block.getInputTargetBlock('STATEMENT');
middleBlock.setCollapsed(true);
chai.assert.equal(this.getPrevious().length, 2);
chai.assert.equal(this.getNext().length, 3);
block.setCollapsed(true);
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
block.setCollapsed(false);
chai.assert.equal(this.getPrevious().length, 2);
chai.assert.equal(this.getNext().length, 3);
middleBlock.setCollapsed(false);
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
});
});
});
});
suite('Comments', function() {
setup(function() {
@@ -492,7 +1030,6 @@ suite('Blocks', function() {
});
suite('Rendered', function() {
setup(function() {
// Let the parent teardown take care of this.
this.workspace = Blockly.inject('blocklyDiv', {
comments: true,
scrollbars: true
@@ -501,6 +1038,9 @@ suite('Blocks', function() {
'<block type="empty_block"/>'
), this.workspace);
});
teardown(function() {
this.workspace.dispose();
});
test('Text', function() {
this.block.setCommentText('test text');
chai.assert.equal(this.block.getCommentText(), 'test text');
@@ -559,4 +1099,56 @@ suite('Blocks', function() {
});
});
});
suite('Icon Management', function() {
suite('Bubbles and Collapsing', function() {
setup(function() {
this.workspace.dispose();
this.workspace = Blockly.inject('blocklyDiv');
});
teardown(function() {
this.workspace.dispose();
});
test('Has Icon', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="statement_block"/>'
), this.workspace);
block.setCommentText('test text');
block.comment.setVisible(true);
chai.assert.isTrue(block.comment.isVisible());
block.setCollapsed(true);
chai.assert.isFalse(block.comment.isVisible());
});
test('Child Has Icon', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="statement_block">' +
' <statement name="STATEMENT">' +
' <block type="statement_block"/>' +
' </statement>' +
'</block>'
), this.workspace);
var childBlock = block.getInputTargetBlock('STATEMENT');
childBlock.setCommentText('test text');
childBlock.comment.setVisible(true);
chai.assert.isTrue(childBlock.comment.isVisible());
block.setCollapsed(true);
chai.assert.isFalse(childBlock.comment.isVisible());
});
test('Next Block Has Icon', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="statement_block">' +
' <next>' +
' <block type="statement_block"/>' +
' </next>' +
'</block>'
), this.workspace);
var nextBlock = block.getNextBlock();
nextBlock.setCommentText('test text');
nextBlock.comment.setVisible(true);
chai.assert.isTrue(nextBlock.comment.isVisible());
block.setCollapsed(true);
chai.assert.isTrue(nextBlock.comment.isVisible());
});
});
});
});

View File

@@ -18,299 +18,265 @@
* limitations under the License.
*/
/**
* @fileoverview Tests for connection DB.
* @author samelh@google.com (Sam El-Husseini)
*/
'use strict';
suite('Connection Database', function() {
setup(function() {
this.database = new Blockly.ConnectionDB();
suite('Connection DB', function() {
function verify_DB_(msg, expected, db) {
var equal = (expected.length == db.connections_.length);
if (equal) {
for (var i = 0; i < expected.length; i++) {
if (expected[i] != db.connections_[i]) {
equal = false;
break;
}
this.assertOrder = function() {
var length = this.database.connections_.length;
for (var i = 1; i < length; i++) {
chai.assert.isAtMost(this.database.connections_[i - 1].y_,
this.database.connections_[i].y_);
}
};
this.createConnection = function(x, y, type, opt_database) {
var workspace = {
connectionDBList: []
};
workspace.connectionDBList[type] = opt_database || this.database;
var connection = new Blockly.RenderedConnection(
{workspace: workspace}, type);
connection.x_ = x;
connection.y_ = y;
return connection;
};
this.createSimpleTestConnections = function() {
for (var i = 0; i < 10; i++) {
var connection = this.createConnection(0, i, Blockly.PREVIOUS_STATEMENT);
this.database.addConnection(connection, i);
}
}
if (equal) {
assertTrue(msg, true);
} else {
assertEquals(msg, expected, db.connections_);
}
}
function helper_createConnection(x, y, type, opt_shared_workspace,
opt_rendered) {
var workspace = opt_shared_workspace ? opt_shared_workspace : {};
if (opt_rendered) {
var conn = new Blockly.RenderedConnection({workspace: workspace}, type);
} else {
var conn = new Blockly.Connection({workspace: workspace}, type);
}
conn.x_ = x;
conn.y_ = y;
return conn;
}
function helper_getNeighbours(db, x, y, radius) {
return db.getNeighbours(helper_createConnection(x, y, Blockly.NEXT_STATEMENT,
null, true), radius);
}
function helper_makeSourceBlock(sharedWorkspace) {
return {workspace: sharedWorkspace,
parentBlock_: null,
getParent: function() { return null; },
movable_: true,
isMovable: function() { return true; },
isShadow: function() { return false; },
isInsertionMarker: function() { return false; },
getFirstStatementConnection: function() { return null; }
};
}
function helper_searchDB(db, x, y, radius, shared_workspace) {
var tempConn = helper_createConnection(x, y,
Blockly.NEXT_STATEMENT, shared_workspace, true);
tempConn.sourceBlock_ = helper_makeSourceBlock(shared_workspace);
tempConn.sourceBlock_.nextConnection = tempConn;
var closest = db.searchForClosest(tempConn, radius, {x: 0, y: 0});
return closest.connection;
}
test('Add connection', function() {
var db = new Blockly.ConnectionDB();
var o2 = {y_: 2, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
db.addConnection(o2);
verify_DB_('Adding connection #2', [o2], db);
var o4 = {y_: 4, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
db.addConnection(o4);
verify_DB_('Adding connection #4', [o2, o4], db);
var o1 = {y_: 1, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
db.addConnection(o1);
verify_DB_('Adding connection #1', [o1, o2, o4], db);
var o3a = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
db.addConnection(o3a);
verify_DB_('Adding connection #3a', [o1, o2, o3a, o4], db);
var o3b = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
db.addConnection(o3b);
verify_DB_('Adding connection #3b', [o1, o2, o3b, o3a, o4], db);
});
test('Remove connection', function() {
var db = new Blockly.ConnectionDB();
var o1 = {y_: 1, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o2 = {y_: 2, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o3a = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o3b = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o3c = {y_: 3, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
var o4 = {y_: 4, sourceBlock_: {},
getSourceBlock: Blockly.Connection.prototype.getSourceBlock};
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);
// TODO: Re-enable once flyout checking is handled by the connection
// (better yet - let it be handled by the flyout, but that's out of the
// scope of this).
test.skip('Add Connection', function() {
var y2 = {y_: 2};
var y4 = {y_: 4};
var y1 = {y_: 1};
var y3a = {y_: 3};
var y3b = {y_: 3};
db.removeConnection_(o2);
verify_DB_('Removing connection #2', [o1, o3a, o3b, o3c, o4], db);
this.database.addConnection(y2, 2);
chai.assert.sameOrderedMembers(
this.database.connections_, [y2]);
db.removeConnection_(o4);
verify_DB_('Removing connection #4', [o1, o3a, o3b, o3c], db);
this.database.addConnection(y4, 4);
chai.assert.sameOrderedMembers(
this.database.connections_, [y2, y4]);
db.removeConnection_(o1);
verify_DB_('Removing connection #1', [o3a, o3b, o3c], db);
this.database.addConnection(y1, 1);
chai.assert.sameOrderedMembers(
this.database.connections_, [y1, y2, y4]);
db.removeConnection_(o3a);
verify_DB_('Removing connection #3a', [o3b, o3c], db);
this.database.addConnection(y3a, 3);
chai.assert.sameOrderedMembers(
this.database.connections_, [y1, y2, y3a, y4]);
db.removeConnection_(o3c);
verify_DB_('Removing connection #3c', [o3b], db);
this.database.addConnection(y3b, 3);
chai.assert.sameOrderedMembers(
this.database.connections_, [y1, y2, y3b, y3a, y4]);
db.removeConnection_(o3b);
verify_DB_('Removing connection #3b', [], db);
});
test.skip('Remove Connection', function() {
var y2 = {y_: 2};
var y4 = {y_: 4};
var y1 = {y_: 1};
var y3a = {y_: 3};
var y3b = {y_: 3};
var y3c = {y_: 3};
test('get Neighbours', function() {
var db = new Blockly.ConnectionDB();
this.database.addConnection(y2, 2);
this.database.addConnection(y4, 4);
this.database.addConnection(y1, 1);
this.database.addConnection(y3c, 3);
this.database.addConnection(y3b, 3);
this.database.addConnection(y3a, 3);
// Search an empty list.
assertEquals(helper_getNeighbours(db,
10 /* x */, 10 /* y */, 100 /* radius */).length, 0);
chai.assert.sameOrderedMembers(
this.database.connections_, [y1, y2, y3a, y3b, y3c, y4]);
// Set up some connections.
for (var i = 0; i < 10; i++) {
db.addConnection(helper_createConnection(0, i,
Blockly.PREVIOUS_STATEMENT, null, true));
}
this.database.removeConnection(y2, 2);
chai.assert.sameOrderedMembers(
this.database.connections_, [y1, y3a, y3b, y3c, y4]);
// Test block belongs at beginning.
var result = helper_getNeighbours(db, 0, 0, 4);
assertEquals(5, result.length);
for (i = 0; i < result.length; i++) {
chai.assert.notEqual(result.indexOf(db.connections_[i]), -1); // contains
}
this.database.removeConnection(y4, 4);
chai.assert.sameOrderedMembers(
this.database.connections_, [y1, y3a, y3b, y3c]);
// Test block belongs at middle.
result = helper_getNeighbours(db, 0, 4, 2);
assertEquals(5, result.length);
for (i = 0; i < result.length; i++) {
chai.assert.notEqual(result.indexOf(db.connections_[i + 2]), -1); // contains
}
this.database.removeConnection(y1, 1);
chai.assert.sameOrderedMembers(
this.database.connections_, [y3a, y3b, y3c]);
// Test block belongs at end.
result = helper_getNeighbours(db, 0, 9, 4);
assertEquals(5, result.length);
for (i = 0; i < result.length; i++) {
chai.assert.notEqual(result.indexOf(db.connections_[i + 5]), -1); // contains
}
this.database.removeConnection(y3a, 3);
chai.assert.sameOrderedMembers(
this.database.connections_, [y3b, y3c]);
// Test block has no neighbours due to being out of range in the x direction.
result = helper_getNeighbours(db, 10, 9, 4);
assertEquals(result.length, 0);
this.database.removeConnection(y3c, 3);
chai.assert.sameOrderedMembers(
this.database.connections_, [y3b]);
// Test block has no neighbours due to being out of range in the y direction.
result = helper_getNeighbours(db, 0, 19, 4);
assertEquals(result.length, 0);
// Test block has no neighbours due to being out of range diagonally.
result = helper_getNeighbours(db, -2, -2, 2);
assertEquals(result.length, 0);
this.database.removeConnection(y3b, 3);
chai.assert.isEmpty(this.database.connections_);
});
suite('Get Neighbors', function() {
test('Empty Database', function() {
var connection = this.createConnection(0, 0, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
chai.assert.isEmpty(this.database.getNeighbours(connection), 100);
});
test('Block At Top', function() {
this.createSimpleTestConnections();
test('Find position for connection', function() {
var db = new Blockly.ConnectionDB();
db.addConnection(helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT,
null, true));
db.addConnection(helper_createConnection(0, 1, Blockly.PREVIOUS_STATEMENT,
null, true));
db.addConnection(helper_createConnection(0, 2, Blockly.PREVIOUS_STATEMENT,
null, true));
db.addConnection(helper_createConnection(0, 4, Blockly.PREVIOUS_STATEMENT,
null, true));
db.addConnection(helper_createConnection(0, 5, Blockly.PREVIOUS_STATEMENT,
null, true));
var checkConnection = this.createConnection(0, 0, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
var neighbors = this.database.getNeighbours(checkConnection, 4);
chai.assert.sameMembers(neighbors, this.database.connections_.slice(0, 5));
});
test('Block In Middle', function() {
this.createSimpleTestConnections();
assertEquals(5, db.connections_.length);
var conn = helper_createConnection(0, 3, Blockly.PREVIOUS_STATEMENT, null,
true);
assertEquals(3, db.findPositionForConnection_(conn));
var checkConnection = this.createConnection(0, 4, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
var neighbors = this.database.getNeighbours(checkConnection, 2);
chai.assert.sameMembers(neighbors, this.database.connections_.slice(2, 7));
});
test('Block At End', function() {
this.createSimpleTestConnections();
var checkConnection = this.createConnection(0, 9, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
var neighbors = this.database.getNeighbours(checkConnection, 4);
chai.assert.sameMembers(neighbors, this.database.connections_.slice(5, 10));
});
test('Out of Range X', function() {
this.createSimpleTestConnections();
var checkConnection = this.createConnection(10, 9, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
var neighbors = this.database.getNeighbours(checkConnection, 4);
chai.assert.isEmpty(neighbors);
});
test('Out of Range Y', function() {
this.createSimpleTestConnections();
var checkConnection = this.createConnection(0, 19, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
var neighbors = this.database.getNeighbours(checkConnection, 4);
chai.assert.isEmpty(neighbors);
});
test('Out of Range Diagonal', function() {
this.createSimpleTestConnections();
var checkConnection = this.createConnection(-2, -2, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
var neighbors = this.database.getNeighbours(checkConnection, 2);
chai.assert.isEmpty(neighbors);
});
});
suite('Ordering', function() {
test('Simple', function() {
for (var i = 0; i < 10; i++) {
var connection = this.createConnection(0, i, Blockly.NEXT_STATEMENT);
this.database.addConnection(connection, i);
}
this.assertOrder();
});
test('Quasi-Random', function() {
var xCoords = [-29, -47, -77, 2, 43, 34, -59, -52, -90, -36, -91, 38,
87, -20, 60, 4, -57, 65, -37, -81, 57, 58, -96, 1, 67, -79, 34, 93,
-90, -99, -62, 4, 11, -36, -51, -72, 3, -50, -24, -45, -92, -38, 37,
24, -47, -73, 79, -20, 99, 43, -10, -87, 19, 35, -62, -36, 49, 86,
-24, -47, -89, 33, -44, 25, -73, -91, 85, 6, 0, 89, -94, 36, -35, 84,
-9, 96, -21, 52, 10, -95, 7, -67, -70, 62, 9, -40, -95, -9, -94, 55,
57, -96, 55, 8, -48, -57, -87, 81, 23, 65];
var yCoords = [-81, 82, 5, 47, 30, 57, -12, 28, 38, 92, -25, -20, 23,
-51, 73, -90, 8, 28, -51, -15, 81, -60, -6, -16, 77, -62, -42, -24,
35, 95, -46, -7, 61, -16, 14, 91, 57, -38, 27, -39, 92, 47, -98, 11,
-33, -72, 64, 38, -64, -88, -35, -59, -76, -94, 45, -25, -100, -95,
63, -97, 45, 98, 99, 34, 27, 52, -18, -45, 66, -32, -38, 70, -73,
-23, 5, -2, -13, -9, 48, 74, -97, -11, 35, -79, -16, -77, 83, -57,
-53, 35, -44, 100, -27, -15, 5, 39, 33, -19, -20, -95];
test('Find connection', function() {
var db = new Blockly.ConnectionDB();
for (var i = 0; i < 10; i++) {
db.addConnection(helper_createConnection(i, 0,
Blockly.PREVIOUS_STATEMENT, null, true));
db.addConnection(helper_createConnection(0, i,
Blockly.PREVIOUS_STATEMENT, null, true));
}
var conn = helper_createConnection(3, 3, Blockly.PREVIOUS_STATEMENT, null,
true);
db.addConnection(conn);
assertEquals(conn, db.connections_[db.findConnection(conn)]);
conn = helper_createConnection(3, 3, Blockly.PREVIOUS_STATEMENT, null, true);
assertEquals(-1, db.findConnection(conn));
var length = xCoords.length;
for (var i = 0; i < length; i++) {
var connection = this.createConnection(xCoords[i], yCoords[i],
Blockly.NEXT_STATEMENT);
this.database.addConnection(connection, yCoords[i]);
}
this.assertOrder();
});
});
// Does not cover logic for isConnectionAllowed
suite('Search For Closest', function() {
setup(function() {
this.allowedStub = null;
test('Ordering', function() {
var db = new Blockly.ConnectionDB();
for (var i = 0; i < 10; i++) {
db.addConnection(helper_createConnection(0, 9 - i,
Blockly.PREVIOUS_STATEMENT), null, true);
}
this.createCheckConnection = function(x, y) {
var checkConnection = this.createConnection(x, y, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
this.allowedStub = sinon.stub(checkConnection, 'isConnectionAllowed')
.callsFake(function(candidate, maxRadius) {
if (this.distanceFrom(candidate) > maxRadius) {
return false;
}
// Ignore non-distance parameters.
return true;
});
return checkConnection;
};
});
teardown(function() {
if (this.allowedStub) {
this.allowedStub.restore();
}
});
test('Empty Database', function() {
var checkConnection = this.createConnection(0, 0, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
chai.assert.isNull(this.database.searchForClosest(
checkConnection, 100, {x: 0, y: 0}).connection);
});
test('Too Far', function() {
var connection = this.createConnection(0, 100, Blockly.PREVIOUS_STATEMENT);
this.database.addConnection(connection, 100);
for (i = 0; i < 10; i++) {
assertEquals(i, db.connections_[i].y_);
}
var checkConnection = this.createConnection(0, 0, Blockly.NEXT_STATEMENT,
new Blockly.ConnectionDB());
chai.assert.isNull(this.database.searchForClosest(
checkConnection, 50, {x: 0, y: 0}).connection);
});
test('Single in Range', function() {
this.createSimpleTestConnections();
// quasi-random
var xCoords = [-29, -47, -77, 2, 43, 34, -59, -52, -90, -36, -91, 38, 87, -20,
60, 4, -57, 65, -37, -81, 57, 58, -96, 1, 67, -79, 34, 93, -90, -99, -62,
4, 11, -36, -51, -72, 3, -50, -24, -45, -92, -38, 37, 24, -47, -73, 79,
-20, 99, 43, -10, -87, 19, 35, -62, -36, 49, 86, -24, -47, -89, 33, -44,
25, -73, -91, 85, 6, 0, 89, -94, 36, -35, 84, -9, 96, -21, 52, 10, -95, 7,
-67, -70, 62, 9, -40, -95, -9, -94, 55, 57, -96, 55, 8, -48, -57, -87, 81,
23, 65];
var yCoords = [-81, 82, 5, 47, 30, 57, -12, 28, 38, 92, -25, -20, 23, -51, 73,
-90, 8, 28, -51, -15, 81, -60, -6, -16, 77, -62, -42, -24, 35, 95, -46,
-7, 61, -16, 14, 91, 57, -38, 27, -39, 92, 47, -98, 11, -33, -72, 64, 38,
-64, -88, -35, -59, -76, -94, 45, -25, -100, -95, 63, -97, 45, 98, 99, 34,
27, 52, -18, -45, 66, -32, -38, 70, -73, -23, 5, -2, -13, -9, 48, 74, -97,
-11, 35, -79, -16, -77, 83, -57, -53, 35, -44, 100, -27, -15, 5, 39, 33,
-19, -20, -95];
for (i = 0; i < xCoords.length; i++) {
db.addConnection(helper_createConnection(xCoords[i], yCoords[i],
Blockly.PREVIOUS_STATEMENT), null, true);
}
var checkConnection = this.createCheckConnection(0, 14);
for (i = 1; i < xCoords.length; i++) {
assertTrue(db.connections_[i].y_ >= db.connections_[i - 1].y_);
}
var last = this.database.connections_[9];
var closest = this.database.searchForClosest(
checkConnection, 5, {x: 0, y: 0}).connection;
chai.assert.equal(last, closest);
});
test('Many in Range', function() {
this.createSimpleTestConnections();
var checkConnection = this.createCheckConnection(0, 10);
var last = this.database.connections_[9];
var closest = this.database.searchForClosest(
checkConnection, 5, {x: 0, y: 0}).connection;
chai.assert.equal(last, closest);
});
test('No Y-Coord Priority', function() {
var connection1 = this.createConnection(6, 6, Blockly.PREVIOUS_STATEMENT);
this.database.addConnection(connection1, 6);
var connection2 = this.createConnection(5, 5, Blockly.PREVIOUS_STATEMENT);
this.database.addConnection(connection2, 5);
var checkConnection = this.createCheckConnection(4, 6);
var closest = this.database.searchForClosest(
checkConnection, 3, {x: 0, y: 0}).connection;
chai.assert.equal(connection2, closest);
});
});
test('Search for closest', function() {
var db = new Blockly.ConnectionDB();
var sharedWorkspace = {id: "Shared workspace"};
// Search an empty list.
assertEquals(null, helper_searchDB(db, 10 /* x */, 10 /* y */,
100 /* radius */));
db.addConnection(helper_createConnection(100, 0, Blockly.PREVIOUS_STATEMENT,
sharedWorkspace, true));
assertEquals(null, helper_searchDB(db, 0, 0, 5, sharedWorkspace));
db = new Blockly.ConnectionDB();
for (var i = 0; i < 10; i++) {
var tempConn = helper_createConnection(0, i, Blockly.PREVIOUS_STATEMENT,
sharedWorkspace, true);
tempConn.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
db.addConnection(tempConn);
}
// Should be at 0, 9.
var last = db.connections_[db.connections_.length - 1];
// Correct connection is last in db; many connections in radius.
assertEquals(last, helper_searchDB(db, 0, 10, 15, sharedWorkspace));
// Nothing nearby.
assertEquals(null, helper_searchDB(db, 100, 100, 3, sharedWorkspace));
// First in db, exact match.
assertEquals(db.connections_[0], helper_searchDB(db, 0, 0, 0, sharedWorkspace));
tempConn = helper_createConnection(6, 6, Blockly.PREVIOUS_STATEMENT,
sharedWorkspace, true);
tempConn.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
db.addConnection(tempConn);
tempConn = helper_createConnection(5, 5, Blockly.PREVIOUS_STATEMENT,
sharedWorkspace, true);
tempConn.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace);
db.addConnection(tempConn);
var result = helper_searchDB(db, 4, 6, 3, sharedWorkspace);
assertEquals(5, result.x_);
assertEquals(5, result.y_);
});
});

View File

@@ -18,323 +18,185 @@
* limitations under the License.
*/
suite('Connections', function() {
suite.skip('Rendered', function() {
function assertAllConnectionsHiddenState(block, hidden) {
var connections = block.getConnections_(true);
for (var i = 0; i < connections.length; i++) {
var connection = connections[i];
if (connection.type == Blockly.PREVIOUS_STATEMENT ||
connection.type == Blockly.OUTPUT_VALUE) {
// Only superior connections on inputs get hidden
continue;
}
if (block.nextConnection && connection === block.nextConnection) {
// The next connection is not hidden when collapsed
continue;
}
assertEquals('Connection ' + i + ' failed', hidden, connections[i].hidden_);
}
}
function assertAllConnectionsHidden(block) {
assertAllConnectionsHiddenState(block, true);
}
function assertAllConnectionsVisible(block) {
assertAllConnectionsHiddenState(block, false);
}
setup(function() {
Blockly.defineBlocksWithJsonArray([{
"type": "stack_block",
"message0": "",
"previousStatement": null,
"nextStatement": null
},
{
"type": "row_block",
"message0": "%1",
"args0": [
{
"type": "input_value",
"name": "INPUT"
}
],
"output": null
},
{
"type": "inputs_block",
"message0": "%1 %2",
"args0": [
{
"type": "input_value",
"name": "INPUT"
},
{
"type": "input_statement",
"name": "STATEMENT"
}
],
"previousStatement": null,
"nextStatement": null
},]);
var toolbox = document.getElementById('toolbox-connections');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
// TODO: Re-enable once headless connections ignore databases.
suite.skip('Connections', function() {
suite('Can Connect With Reason', function() {
test('Target Null', function() {
var connection = new Blockly.Connection({}, Blockly.INPUT_VALUE);
chai.assert.equal(connection.canConnectWithReason_(null),
Blockly.Connection.REASON_TARGET_NULL);
});
test('Target Self', function() {
var block = {workspace: 1};
var connection1 = new Blockly.Connection(block, Blockly.INPUT_VALUE);
var connection2 = new Blockly.Connection(block, Blockly.OUTPUT_VALUE);
teardown(function() {
delete Blockly.Blocks['stack_block'];
delete Blockly.Blocks['row_block'];
delete Blockly.Blocks['inputs_block'];
this.workspace.dispose();
chai.assert.equal(connection1.canConnectWithReason_(connection2),
Blockly.Connection.REASON_SELF_CONNECTION);
});
test('Different Workspaces', function() {
var connection1 = new Blockly.Connection(
{workspace: 1}, Blockly.INPUT_VALUE);
var connection2 = new Blockly.Connection(
{workspace: 2}, Blockly.OUTPUT_VALUE);
suite('Row collapsing', function() {
chai.assert.equal(connection1.canConnectWithReason_(connection2),
Blockly.Connection.REASON_DIFFERENT_WORKSPACES);
});
suite('Types', function() {
setup(function() {
var blockA = this.workspace.newBlock('row_block');
var blockB = this.workspace.newBlock('row_block');
var blockC = this.workspace.newBlock('row_block');
blockA.inputList[0].connection.connect(blockB.outputConnection);
blockA.setCollapsed(true);
assertEquals(blockA, blockB.getParent());
assertNull(blockC.getParent());
assertTrue(blockA.isCollapsed());
assertAllConnectionsHidden(blockA);
assertAllConnectionsHidden(blockB);
assertAllConnectionsVisible(blockC);
this.blocks = {
A: blockA,
B: blockB,
C: blockC
};
// We have to declare each separately so that the connections belong
// on different blocks.
var prevBlock = { isShadow: function() {}};
var nextBlock = { isShadow: function() {}};
var outBlock = { isShadow: function() {}};
var inBlock = { isShadow: function() {}};
this.previous = new Blockly.Connection(
prevBlock, Blockly.PREVIOUS_STATEMENT);
this.next = new Blockly.Connection(
nextBlock, Blockly.NEXT_STATEMENT);
this.output = new Blockly.Connection(
outBlock, Blockly.OUTPUT_VALUE);
this.input = new Blockly.Connection(
inBlock, Blockly.INPUT_VALUE);
});
test('Add to end', function() {
var blocks = this.blocks;
blocks.B.inputList[0].connection.connect(blocks.C.outputConnection);
assertAllConnectionsHidden(blocks.C);
test('Previous, Next', function() {
chai.assert.equal(this.previous.canConnectWithReason_(this.next),
Blockly.Connection.CAN_CONNECT);
});
test('Add to end w/inferior', function() {
var blocks = this.blocks;
blocks.C.outputConnection.connect(blocks.B.inputList[0].connection);
assertAllConnectionsHidden(blocks.C);
test('Previous, Output', function() {
chai.assert.equal(this.previous.canConnectWithReason_(this.output),
Blockly.Connection.REASON_WRONG_TYPE);
});
test('Add to middle', function() {
var blocks = this.blocks;
blocks.A.inputList[0].connection.connect(blocks.C.outputConnection);
assertAllConnectionsHidden(blocks.C);
test('Previous, Input', function() {
chai.assert.equal(this.previous.canConnectWithReason_(this.input),
Blockly.Connection.REASON_WRONG_TYPE);
});
test('Add to middle w/inferior', function() {
var blocks = this.blocks;
blocks.C.outputConnection.connect(blocks.A.inputList[0].connection);
assertAllConnectionsHidden(blocks.C);
test('Next, Previous', function() {
chai.assert.equal(this.next.canConnectWithReason_(this.previous),
Blockly.Connection.CAN_CONNECT);
});
test('Remove simple', function() {
var blocks = this.blocks;
blocks.B.unplug();
assertAllConnectionsVisible(blocks.B);
test('Next, Output', function() {
chai.assert.equal(this.next.canConnectWithReason_(this.output),
Blockly.Connection.REASON_WRONG_TYPE);
});
test('Remove middle', function() {
var blocks = this.blocks;
blocks.B.inputList[0].connection.connect(blocks.C.outputConnection);
blocks.B.unplug(false);
assertAllConnectionsVisible(blocks.B);
assertAllConnectionsVisible(blocks.C);
test('Next, Input', function() {
chai.assert.equal(this.next.canConnectWithReason_(this.input),
Blockly.Connection.REASON_WRONG_TYPE);
});
test('Remove middle healing', function() {
var blocks = this.blocks;
blocks.B.inputList[0].connection.connect(blocks.C.outputConnection);
blocks.B.unplug(true);
assertAllConnectionsVisible(blocks.B);
assertAllConnectionsHidden(blocks.C);
test('Output, Previous', function() {
chai.assert.equal(this.output.canConnectWithReason_(this.previous),
Blockly.Connection.REASON_WRONG_TYPE);
});
test('Add before', function() {
var blocks = this.blocks;
blocks.C.inputList[0].connection.connect(blocks.A.outputConnection);
// Connecting a collapsed block to another block doesn't change any hidden state
assertAllConnectionsHidden(blocks.A);
assertAllConnectionsVisible(blocks.C);
test('Output, Next', function() {
chai.assert.equal(this.output.canConnectWithReason_(this.next),
Blockly.Connection.REASON_WRONG_TYPE);
});
test('Remove front', function() {
var blocks = this.blocks;
blocks.B.inputList[0].connection.connect(blocks.C.outputConnection);
blocks.A.inputList[0].connection.disconnect();
assertTrue(blocks.A.isCollapsed());
assertAllConnectionsHidden(blocks.A);
assertAllConnectionsVisible(blocks.B);
assertAllConnectionsVisible(blocks.C);
test('Output, Input', function() {
chai.assert.equal(this.output.canConnectWithReason_(this.input),
Blockly.Connection.CAN_CONNECT);
});
test('Uncollapse', function() {
var blocks = this.blocks;
blocks.B.inputList[0].connection.connect(blocks.C.outputConnection);
blocks.A.setCollapsed(false);
assertFalse(blocks.A.isCollapsed());
assertAllConnectionsVisible(blocks.A);
assertAllConnectionsVisible(blocks.B);
assertAllConnectionsVisible(blocks.C);
test('Input, Previous', function() {
chai.assert.equal(this.input.canConnectWithReason_(this.previous),
Blockly.Connection.REASON_WRONG_TYPE);
});
test('Input, Next', function() {
chai.assert.equal(this.input.canConnectWithReason_(this.next),
Blockly.Connection.REASON_WRONG_TYPE);
});
test('Input, Output', function() {
chai.assert.equal(this.input.canConnectWithReason_(this.output),
Blockly.Connection.CAN_CONNECT);
});
});
suite('Statement collapsing', function() {
setup(function() {
var blockA = this.workspace.newBlock('inputs_block');
var blockB = this.workspace.newBlock('inputs_block');
var blockC = this.workspace.newBlock('inputs_block');
suite('Shadows', function() {
test('Previous Shadow', function() {
var prevBlock = { isShadow: function() { return true; }};
var nextBlock = { isShadow: function() { return false; }};
var prev = new Blockly.Connection(prevBlock, Blockly.PREVIOUS_STATEMENT);
var next = new Blockly.Connection(nextBlock, Blockly.NEXT_STATEMENT);
blockA.getInput('STATEMENT').connection.connect(blockB.previousConnection);
blockA.setCollapsed(true);
assertEquals(blockA, blockB.getParent());
assertNull(blockC.getParent());
assertTrue(blockA.isCollapsed());
assertAllConnectionsHidden(blockA);
assertAllConnectionsHidden(blockB);
assertAllConnectionsVisible(blockC);
this.blocks = {
A: blockA,
B: blockB,
C: blockC
};
chai.assert.equal(prev.canConnectWithReason_(next),
Blockly.Connection.CAN_CONNECT);
});
test('Next Shadow', function() {
var prevBlock = { isShadow: function() { return false; }};
var nextBlock = { isShadow: function() { return true; }};
var prev = new Blockly.Connection(prevBlock, Blockly.PREVIOUS_STATEMENT);
var next = new Blockly.Connection(nextBlock, Blockly.NEXT_STATEMENT);
test('Add to statement', function() {
var blocks = this.blocks;
blocks.B.getInput('STATEMENT').connection.connect(blocks.C.previousConnection);
assertAllConnectionsHidden(blocks.C);
chai.assert.equal(prev.canConnectWithReason_(next),
Blockly.Connection.REASON_SHADOW_PARENT);
});
test('Prev and Next Shadow', function() {
var prevBlock = { isShadow: function() { return true; }};
var nextBlock = { isShadow: function() { return true; }};
var prev = new Blockly.Connection(prevBlock, Blockly.PREVIOUS_STATEMENT);
var next = new Blockly.Connection(nextBlock, Blockly.NEXT_STATEMENT);
test('Insert in statement', function() {
var blocks = this.blocks;
blocks.A.getInput('STATEMENT').connection.connect(blocks.C.previousConnection);
assertAllConnectionsHidden(blocks.C);
chai.assert.equal(prev.canConnectWithReason_(next),
Blockly.Connection.CAN_CONNECT);
});
test('Output Shadow', function() {
var outBlock = { isShadow: function() { return true; }};
var inBlock = { isShadow: function() { return false; }};
var outCon = new Blockly.Connection(outBlock, Blockly.OUTPUT_VALUE);
var inCon = new Blockly.Connection(inBlock, Blockly.INPUT_VALUE);
test('Add to hidden next', function() {
var blocks = this.blocks;
blocks.B.nextConnection.connect(blocks.C.previousConnection);
assertAllConnectionsHidden(blocks.C);
chai.assert.equal(outCon.canConnectWithReason_(inCon),
Blockly.Connection.CAN_CONNECT);
});
test('Input Shadow', function() {
var outBlock = { isShadow: function() { return false; }};
var inBlock = { isShadow: function() { return true; }};
var outCon = new Blockly.Connection(outBlock, Blockly.OUTPUT_VALUE);
var inCon = new Blockly.Connection(inBlock, Blockly.INPUT_VALUE);
test('Remove simple', function() {
var blocks = this.blocks;
blocks.B.unplug();
assertAllConnectionsVisible(blocks.B);
chai.assert.equal(outCon.canConnectWithReason_(inCon),
Blockly.Connection.REASON_SHADOW_PARENT);
});
test('Output and Input Shadow', function() {
var outBlock = { isShadow: function() { return true; }};
var inBlock = { isShadow: function() { return true; }};
var outCon = new Blockly.Connection(outBlock, Blockly.OUTPUT_VALUE);
var inCon = new Blockly.Connection(inBlock, Blockly.INPUT_VALUE);
test('Remove middle', function() {
var blocks = this.blocks;
blocks.B.nextConnection.connect(blocks.C.previousConnection);
blocks.B.unplug(false);
assertAllConnectionsVisible(blocks.B);
assertAllConnectionsVisible(blocks.C);
});
test('Remove middle healing', function() {
var blocks = this.blocks;
blocks.B.nextConnection.connect(blocks.C.previousConnection);
blocks.B.unplug(true);
assertAllConnectionsVisible(blocks.B);
assertAllConnectionsHidden(blocks.C);
});
test('Add before', function() {
var blocks = this.blocks;
blocks.C.getInput('STATEMENT').connection.connect(blocks.A.previousConnection);
assertAllConnectionsHidden(blocks.A);
assertAllConnectionsHidden(blocks.B);
assertAllConnectionsVisible(blocks.C);
});
test('Remove front', function() {
var blocks = this.blocks;
blocks.B.nextConnection.connect(blocks.C.previousConnection);
blocks.A.getInput('STATEMENT').connection.disconnect();
assertTrue(blocks.A.isCollapsed());
assertAllConnectionsHidden(blocks.A);
assertAllConnectionsVisible(blocks.B);
assertAllConnectionsVisible(blocks.C);
});
test('Uncollapse', function() {
var blocks = this.blocks;
blocks.B.nextConnection.connect(blocks.C.previousConnection);
blocks.A.setCollapsed(false);
assertFalse(blocks.A.isCollapsed());
assertAllConnectionsVisible(blocks.A);
assertAllConnectionsVisible(blocks.B);
assertAllConnectionsVisible(blocks.C);
});
});
suite('Collapsing with shadows', function() {
setup(function() {
var blockA = this.workspace.newBlock('inputs_block');
var blockB = this.workspace.newBlock('inputs_block');
var blockC = this.workspace.newBlock('inputs_block');
var blockD = this.workspace.newBlock('row_block');
blockB.setShadow(true);
var shadowStatement = Blockly.Xml.blockToDom(blockB, true /* noid */);
blockB.setShadow(false);
blockD.setShadow(true);
var shadowValue = Blockly.Xml.blockToDom(blockD, true /* noid */);
blockD.setShadow(false);
var connection = blockA.getInput('STATEMENT').connection;
connection.setShadowDom(shadowStatement);
connection.connect(blockB.previousConnection);
connection = blockA.getInput('INPUT').connection;
connection.setShadowDom(shadowValue);
connection.connect(blockD.outputConnection);
blockA.setCollapsed(true);
assertEquals(blockA, blockB.getParent());
assertNull(blockC.getParent());
assertTrue(blockA.isCollapsed());
assertAllConnectionsHidden(blockA);
assertAllConnectionsHidden(blockB);
assertAllConnectionsVisible(blockC);
this.blocks = {
A: blockA,
B: blockB,
C: blockC,
D: blockD
};
});
test('Reveal shadow statement', function() {
var blocks = this.blocks;
var connection = blocks.A.getInput('STATEMENT').connection;
connection.disconnect();
var shadowBlock = connection.targetBlock();
assertTrue(shadowBlock.isShadow());
assertAllConnectionsHidden(shadowBlock);
});
test('Reveal shadow value', function() {
var blocks = this.blocks;
var connection = blocks.A.getInput('INPUT').connection;
connection.disconnect();
var shadowBlock = connection.targetBlock();
assertTrue(shadowBlock.isShadow());
assertAllConnectionsHidden(shadowBlock);
chai.assert.equal(outCon.canConnectWithReason_(inCon),
Blockly.Connection.CAN_CONNECT);
});
});
});
suite('Check Types', function() {
setup(function() {
this.con1 = new Blockly.Connection({}, Blockly.PREVIOUS_STATEMENT);
this.con2 = new Blockly.Connection({}, Blockly.NEXT_STATEMENT);
});
test('No Types', function() {
chai.assert.isTrue(this.con1.checkType_(this.con2));
});
test('Same Type', function() {
this.con1.setCheck('type1');
this.con2.setCheck('type1');
chai.assert.isTrue(this.con1.checkType_(this.con2));
});
test('Same Types', function() {
this.con1.setCheck(['type1', 'type2']);
this.con2.setCheck(['type1', 'type2']);
chai.assert.isTrue(this.con1.checkType_(this.con2));
});
test('Single Same Type', function() {
this.con1.setCheck(['type1', 'type2']);
this.con2.setCheck(['type1', 'type3']);
chai.assert.isTrue(this.con1.checkType_(this.con2));
});
test('One Typed, One Promiscuous', function() {
this.con1.setCheck('type1');
chai.assert.isTrue(this.con1.checkType_(this.con2));
});
test('No Compatible Types', function() {
this.con1.setCheck('type1');
this.con2.setCheck('type2');
chai.assert.isFalse(this.con1.checkType_(this.con2));
});
});
});

View File

@@ -29,6 +29,7 @@
<script src="comment_test.js"></script>
<script src="connection_db_test.js"></script>
<script src="connection_test.js"></script>
<script src="connection_db_test.js"></script>
<script src="cursor_test.js"></script>
<script src="dropdowndiv_test.js"></script>
<script src="event_test.js"></script>