mirror of
https://github.com/google/blockly.git
synced 2026-01-10 02:17:09 +01:00
Update connection tests to directly use the type checker
This commit is contained in:
@@ -250,29 +250,7 @@ Blockly.Connection.prototype.isConnected = function() {
|
||||
* an error code otherwise.
|
||||
*/
|
||||
Blockly.Connection.prototype.canConnectWithReason = function(target) {
|
||||
return this.sourceBlock_.workspace.connectionTypeChecker.canConnectWithReason(this, target);
|
||||
// if (!target) {
|
||||
// return Blockly.Connection.REASON_TARGET_NULL;
|
||||
// }
|
||||
// if (this.isSuperior()) {
|
||||
// var blockA = this.sourceBlock_;
|
||||
// var blockB = target.getSourceBlock();
|
||||
// } else {
|
||||
// var blockB = this.sourceBlock_;
|
||||
// var blockA = target.getSourceBlock();
|
||||
// }
|
||||
// if (blockA && blockA == blockB) {
|
||||
// return Blockly.Connection.REASON_SELF_CONNECTION;
|
||||
// } else if (target.type != Blockly.OPPOSITE_TYPE[this.type]) {
|
||||
// return Blockly.Connection.REASON_WRONG_TYPE;
|
||||
// } else if (blockA && blockB && blockA.workspace !== blockB.workspace) {
|
||||
// return Blockly.Connection.REASON_DIFFERENT_WORKSPACES;
|
||||
// } else if (!this.checkType(target)) {
|
||||
// return Blockly.Connection.REASON_CHECKS_FAILED;
|
||||
// } else if (blockA.isShadow() && !blockB.isShadow()) {
|
||||
// return Blockly.Connection.REASON_SHADOW_PARENT;
|
||||
// }
|
||||
// return Blockly.Connection.CAN_CONNECT;
|
||||
return this.getConnectionTypeChecker().canConnectWithReason(this, target);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -284,57 +262,60 @@ Blockly.Connection.prototype.canConnectWithReason = function(target) {
|
||||
*/
|
||||
Blockly.Connection.prototype.checkConnection = function(target) {
|
||||
|
||||
var checker = this.sourceBlock_.workspace.connectionTypeChecker;
|
||||
var checker = this.getConnectionTypeChecker();
|
||||
var reason = checker.canConnectWithReason(this, target);
|
||||
if (reason != Blockly.Connection.CAN_CONNECT) {
|
||||
throw Error(checker.getErrorMessage(reason, this, target));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the two connections can be dragged to connect to each other.
|
||||
* This is used by the connection database when searching for the closest
|
||||
* connection.
|
||||
* @param {!Blockly.Connection} candidate A nearby connection to check, which
|
||||
* must be a previous connection.
|
||||
* @return {boolean} True if the connection is allowed, false otherwise.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Connection.prototype.canConnectToPrevious_ = function(candidate) {
|
||||
if (this.targetConnection) {
|
||||
// This connection is already occupied.
|
||||
// A next connection will never disconnect itself mid-drag.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't let blocks try to connect to themselves or ones they nest.
|
||||
if (Blockly.draggingConnections.indexOf(candidate) != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!candidate.targetConnection) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var targetBlock = candidate.targetBlock();
|
||||
// If it is connected to a real block, game over.
|
||||
if (!targetBlock.isInsertionMarker()) {
|
||||
return false;
|
||||
}
|
||||
// If it's connected to an insertion marker but that insertion marker
|
||||
// is the first block in a stack, it's still fine. If that insertion
|
||||
// marker is in the middle of a stack, it won't work.
|
||||
return !targetBlock.getPreviousBlock();
|
||||
Blockly.Connection.prototype.getConnectionTypeChecker = function() {
|
||||
return this.sourceBlock_.workspace.connectionTypeChecker;
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Check if the two connections can be dragged to connect to each other.
|
||||
// * This is used by the connection database when searching for the closest
|
||||
// * connection.
|
||||
// * @param {!Blockly.Connection} candidate A nearby connection to check, which
|
||||
// * must be a previous connection.
|
||||
// * @return {boolean} True if the connection is allowed, false otherwise.
|
||||
// * @private
|
||||
// */
|
||||
// Blockly.Connection.prototype.canConnectToPrevious_ = function(candidate) {
|
||||
// if (this.targetConnection) {
|
||||
// // This connection is already occupied.
|
||||
// // A next connection will never disconnect itself mid-drag.
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // Don't let blocks try to connect to themselves or ones they nest.
|
||||
// if (Blockly.draggingConnections.indexOf(candidate) != -1) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// if (!candidate.targetConnection) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// var targetBlock = candidate.targetBlock();
|
||||
// // If it is connected to a real block, game over.
|
||||
// if (!targetBlock.isInsertionMarker()) {
|
||||
// return false;
|
||||
// }
|
||||
// // If it's connected to an insertion marker but that insertion marker
|
||||
// // is the first block in a stack, it's still fine. If that insertion
|
||||
// // marker is in the middle of a stack, it won't work.
|
||||
// return !targetBlock.getPreviousBlock();
|
||||
// };
|
||||
|
||||
/**
|
||||
* Check if the two connections can be dragged to connect to each other.
|
||||
* @param {!Blockly.Connection} candidate A nearby connection to check.
|
||||
* @return {boolean} True if the connection is allowed, false otherwise.
|
||||
*/
|
||||
Blockly.Connection.prototype.isConnectionAllowed = function(candidate) {
|
||||
var checker = this.sourceBlock_.workspace.connectionTypeChecker;
|
||||
return checker.isConnectionAllowed(this, candidate);
|
||||
return this.getConnectionTypeChecker().isConnectionAllowed(this, candidate);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -357,7 +338,7 @@ Blockly.Connection.prototype.connect = function(otherConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
var checker = this.sourceBlock_.workspace.connectionTypeChecker;
|
||||
var checker = this.getConnectionTypeChecker();
|
||||
var reason = checker.canConnectWithReason(this, otherConnection);
|
||||
if (reason != Blockly.Connection.CAN_CONNECT) {
|
||||
throw Error(checker.getErrorMessage(reason, this, otherConnection));
|
||||
@@ -538,8 +519,7 @@ Blockly.Connection.prototype.targetBlock = function() {
|
||||
* @return {boolean} True if the connections share a type.
|
||||
*/
|
||||
Blockly.Connection.prototype.checkType = function(otherConnection) {
|
||||
return this.sourceBlock_.workspace.connectionTypeChecker.checkType(
|
||||
this, otherConnection);
|
||||
return this.getConnectionTypeChecker().checkType(this, otherConnection);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,47 +53,32 @@ Blockly.ConnectionTypeChecker.prototype.getErrorMessage = function(errorCode,
|
||||
* an error code otherwise.
|
||||
*/
|
||||
Blockly.ConnectionTypeChecker.prototype.canConnectWithReason = function(one, two) {
|
||||
if (!two) {
|
||||
if (!one || !two) {
|
||||
return Blockly.Connection.REASON_TARGET_NULL;
|
||||
}
|
||||
if (one.isSuperior()) {
|
||||
var blockA = one.sourceBlock_;
|
||||
var blockA = one.getSourceBlock();
|
||||
var blockB = two.getSourceBlock();
|
||||
} else {
|
||||
var blockB = one.sourceBlock_;
|
||||
var blockB = one.getSourceBlock();
|
||||
var blockA = two.getSourceBlock();
|
||||
}
|
||||
|
||||
// TODO (fenichel): The null checks seem like they're only for making tests
|
||||
// work better.
|
||||
if (blockA && blockA == blockB) {
|
||||
return Blockly.Connection.REASON_SELF_CONNECTION;
|
||||
} else if (two.type != Blockly.OPPOSITE_TYPE[one.type]) {
|
||||
return Blockly.Connection.REASON_WRONG_TYPE;
|
||||
} else if (blockA && blockB && blockA.workspace !== blockB.workspace) {
|
||||
return Blockly.Connection.REASON_DIFFERENT_WORKSPACES;
|
||||
} else if (!this.checkType(one, two)) {
|
||||
return Blockly.Connection.REASON_CHECKS_FAILED;
|
||||
} else if (blockA.isShadow() && !blockB.isShadow()) {
|
||||
return Blockly.Connection.REASON_SHADOW_PARENT;
|
||||
} else if (!this.checkType(one, two)) {
|
||||
return Blockly.Connection.REASON_CHECKS_FAILED;
|
||||
}
|
||||
return Blockly.Connection.CAN_CONNECT;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the current connection and target connection are compatible
|
||||
* and throws an exception if they are not.
|
||||
* @param {!Blockly.Connection} one The connection to check compatibility
|
||||
* with.
|
||||
* @param {!Blockly.Connection} two The connection to check compatibility
|
||||
* with.
|
||||
* @package
|
||||
*/
|
||||
// Blockly.ConnectionTypeChecker.prototype.checkConnection = function(one, two) {
|
||||
// var reason = one.canConnectWithReason(two);
|
||||
// if (reason != Blockly.Connection.CAN_CONNECT) {
|
||||
// throw Error(this.getErrorMessage_(reason, one, two));
|
||||
// }
|
||||
// };
|
||||
|
||||
/**
|
||||
* Is this connection compatible with another connection with respect to the
|
||||
* value type system. E.g. square_root("Hello") is not compatible.
|
||||
|
||||
@@ -4,11 +4,23 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
suite('Connections', function() {
|
||||
suite('Connection type checker', function() {
|
||||
suiteSetup(function() {
|
||||
this.checker = new Blockly.ConnectionTypeChecker();
|
||||
});
|
||||
suite('Can Connect With Reason', function() {
|
||||
function assertReasonHelper(checker, one, two, reason) {
|
||||
chai.assert.equal(checker.canConnectWithReason(one, two), reason);
|
||||
// Order should not matter.
|
||||
chai.assert.equal(checker.canConnectWithReason(two, one), reason);
|
||||
}
|
||||
|
||||
test('Target Null', function() {
|
||||
var connection = new Blockly.Connection({}, Blockly.INPUT_VALUE);
|
||||
chai.assert.equal(connection.canConnectWithReason(null),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
connection,
|
||||
null,
|
||||
Blockly.Connection.REASON_TARGET_NULL);
|
||||
});
|
||||
test('Target Self', function() {
|
||||
@@ -16,7 +28,10 @@ suite('Connections', function() {
|
||||
var connection1 = new Blockly.Connection(block, Blockly.INPUT_VALUE);
|
||||
var connection2 = new Blockly.Connection(block, Blockly.OUTPUT_VALUE);
|
||||
|
||||
chai.assert.equal(connection1.canConnectWithReason(connection2),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
connection1,
|
||||
connection2,
|
||||
Blockly.Connection.REASON_SELF_CONNECTION);
|
||||
});
|
||||
test('Different Workspaces', function() {
|
||||
@@ -25,7 +40,10 @@ suite('Connections', function() {
|
||||
var connection2 = new Blockly.Connection(
|
||||
{workspace: 2}, Blockly.OUTPUT_VALUE);
|
||||
|
||||
chai.assert.equal(connection1.canConnectWithReason(connection2),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
connection1,
|
||||
connection2,
|
||||
Blockly.Connection.REASON_DIFFERENT_WORKSPACES);
|
||||
});
|
||||
suite('Types', function() {
|
||||
@@ -46,51 +64,87 @@ suite('Connections', function() {
|
||||
inBlock, Blockly.INPUT_VALUE);
|
||||
});
|
||||
test('Previous, Next', function() {
|
||||
chai.assert.equal(this.previous.canConnectWithReason(this.next),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.previous,
|
||||
this.next,
|
||||
Blockly.Connection.CAN_CONNECT);
|
||||
});
|
||||
test('Previous, Output', function() {
|
||||
chai.assert.equal(this.previous.canConnectWithReason(this.output),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.previous,
|
||||
this.output,
|
||||
Blockly.Connection.REASON_WRONG_TYPE);
|
||||
});
|
||||
test('Previous, Input', function() {
|
||||
chai.assert.equal(this.previous.canConnectWithReason(this.input),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.previous,
|
||||
this.input,
|
||||
Blockly.Connection.REASON_WRONG_TYPE);
|
||||
});
|
||||
test('Next, Previous', function() {
|
||||
chai.assert.equal(this.next.canConnectWithReason(this.previous),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.next,
|
||||
this.previous,
|
||||
Blockly.Connection.CAN_CONNECT);
|
||||
});
|
||||
test('Next, Output', function() {
|
||||
chai.assert.equal(this.next.canConnectWithReason(this.output),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.next,
|
||||
this.output,
|
||||
Blockly.Connection.REASON_WRONG_TYPE);
|
||||
});
|
||||
test('Next, Input', function() {
|
||||
chai.assert.equal(this.next.canConnectWithReason(this.input),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.next,
|
||||
this.input,
|
||||
Blockly.Connection.REASON_WRONG_TYPE);
|
||||
});
|
||||
test('Output, Previous', function() {
|
||||
chai.assert.equal(this.output.canConnectWithReason(this.previous),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.previous,
|
||||
this.output,
|
||||
Blockly.Connection.REASON_WRONG_TYPE);
|
||||
});
|
||||
test('Output, Next', function() {
|
||||
chai.assert.equal(this.output.canConnectWithReason(this.next),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.output,
|
||||
this.next,
|
||||
Blockly.Connection.REASON_WRONG_TYPE);
|
||||
});
|
||||
test('Output, Input', function() {
|
||||
chai.assert.equal(this.output.canConnectWithReason(this.input),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.output,
|
||||
this.input,
|
||||
Blockly.Connection.CAN_CONNECT);
|
||||
});
|
||||
test('Input, Previous', function() {
|
||||
chai.assert.equal(this.input.canConnectWithReason(this.previous),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.previous,
|
||||
this.input,
|
||||
Blockly.Connection.REASON_WRONG_TYPE);
|
||||
});
|
||||
test('Input, Next', function() {
|
||||
chai.assert.equal(this.input.canConnectWithReason(this.next),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.input,
|
||||
this.next,
|
||||
Blockly.Connection.REASON_WRONG_TYPE);
|
||||
});
|
||||
test('Input, Output', function() {
|
||||
chai.assert.equal(this.input.canConnectWithReason(this.output),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
this.input,
|
||||
this.output,
|
||||
Blockly.Connection.CAN_CONNECT);
|
||||
});
|
||||
});
|
||||
@@ -101,7 +155,10 @@ suite('Connections', function() {
|
||||
var prev = new Blockly.Connection(prevBlock, Blockly.PREVIOUS_STATEMENT);
|
||||
var next = new Blockly.Connection(nextBlock, Blockly.NEXT_STATEMENT);
|
||||
|
||||
chai.assert.equal(prev.canConnectWithReason(next),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
prev,
|
||||
next,
|
||||
Blockly.Connection.CAN_CONNECT);
|
||||
});
|
||||
test('Next Shadow', function() {
|
||||
@@ -110,7 +167,10 @@ suite('Connections', function() {
|
||||
var prev = new Blockly.Connection(prevBlock, Blockly.PREVIOUS_STATEMENT);
|
||||
var next = new Blockly.Connection(nextBlock, Blockly.NEXT_STATEMENT);
|
||||
|
||||
chai.assert.equal(prev.canConnectWithReason(next),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
prev,
|
||||
next,
|
||||
Blockly.Connection.REASON_SHADOW_PARENT);
|
||||
});
|
||||
test('Prev and Next Shadow', function() {
|
||||
@@ -119,7 +179,10 @@ suite('Connections', function() {
|
||||
var prev = new Blockly.Connection(prevBlock, Blockly.PREVIOUS_STATEMENT);
|
||||
var next = new Blockly.Connection(nextBlock, Blockly.NEXT_STATEMENT);
|
||||
|
||||
chai.assert.equal(prev.canConnectWithReason(next),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
prev,
|
||||
next,
|
||||
Blockly.Connection.CAN_CONNECT);
|
||||
});
|
||||
test('Output Shadow', function() {
|
||||
@@ -128,7 +191,10 @@ suite('Connections', function() {
|
||||
var outCon = new Blockly.Connection(outBlock, Blockly.OUTPUT_VALUE);
|
||||
var inCon = new Blockly.Connection(inBlock, Blockly.INPUT_VALUE);
|
||||
|
||||
chai.assert.equal(outCon.canConnectWithReason(inCon),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
outCon,
|
||||
inCon,
|
||||
Blockly.Connection.CAN_CONNECT);
|
||||
});
|
||||
test('Input Shadow', function() {
|
||||
@@ -137,7 +203,10 @@ suite('Connections', function() {
|
||||
var outCon = new Blockly.Connection(outBlock, Blockly.OUTPUT_VALUE);
|
||||
var inCon = new Blockly.Connection(inBlock, Blockly.INPUT_VALUE);
|
||||
|
||||
chai.assert.equal(outCon.canConnectWithReason(inCon),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
outCon,
|
||||
inCon,
|
||||
Blockly.Connection.REASON_SHADOW_PARENT);
|
||||
});
|
||||
test('Output and Input Shadow', function() {
|
||||
@@ -146,7 +215,10 @@ suite('Connections', function() {
|
||||
var outCon = new Blockly.Connection(outBlock, Blockly.OUTPUT_VALUE);
|
||||
var inCon = new Blockly.Connection(inBlock, Blockly.INPUT_VALUE);
|
||||
|
||||
chai.assert.equal(outCon.canConnectWithReason(inCon),
|
||||
assertReasonHelper(
|
||||
this.checker,
|
||||
outCon,
|
||||
inCon,
|
||||
Blockly.Connection.CAN_CONNECT);
|
||||
});
|
||||
});
|
||||
@@ -156,32 +228,38 @@ suite('Connections', function() {
|
||||
this.con1 = new Blockly.Connection({}, Blockly.PREVIOUS_STATEMENT);
|
||||
this.con2 = new Blockly.Connection({}, Blockly.NEXT_STATEMENT);
|
||||
});
|
||||
function assertCheckTypes(checker, one, two) {
|
||||
chai.assert.isTrue(checker.checkType(one, two));
|
||||
// Order should not matter.
|
||||
chai.assert.isTrue(checker.checkType(one, two));
|
||||
}
|
||||
test('No Types', function() {
|
||||
chai.assert.isTrue(this.con1.checkType((this.con2)));
|
||||
assertCheckTypes(this.checker, this.con1, this.con2);
|
||||
chai.assert.isTrue(this.checker.checkType(this.con1, this.con2));
|
||||
});
|
||||
test('Same Type', function() {
|
||||
this.con1.setCheck('type1');
|
||||
this.con2.setCheck('type1');
|
||||
chai.assert.isTrue(this.con1.checkType((this.con2)));
|
||||
assertCheckTypes(this.checker, this.con1, this.con2);
|
||||
});
|
||||
test('Same Types', function() {
|
||||
this.con1.setCheck(['type1', 'type2']);
|
||||
this.con2.setCheck(['type1', 'type2']);
|
||||
chai.assert.isTrue(this.con1.checkType((this.con2)));
|
||||
assertCheckTypes(this.checker, this.con1, 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)));
|
||||
assertCheckTypes(this.checker, this.con1, this.con2);
|
||||
});
|
||||
test('One Typed, One Promiscuous', function() {
|
||||
this.con1.setCheck('type1');
|
||||
chai.assert.isTrue(this.con1.checkType((this.con2)));
|
||||
assertCheckTypes(this.checker, this.con1, this.con2);
|
||||
});
|
||||
test('No Compatible Types', function() {
|
||||
this.con1.setCheck('type1');
|
||||
this.con2.setCheck('type2');
|
||||
chai.assert.isFalse(this.con1.checkType((this.con2)));
|
||||
chai.assert.isFalse(this.checker.checkType(this.con1, this.con2));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user