2017-04-20 19:17:05 -04:00
|
|
|
const test = require('tap').test;
|
|
|
|
const Blocks = require('../../src/engine/blocks');
|
2018-06-20 10:32:36 -04:00
|
|
|
const Variable = require('../../src/engine/variable');
|
|
|
|
const adapter = require('../../src/engine/adapter');
|
|
|
|
const events = require('../fixtures/events.json');
|
2019-01-28 19:30:42 -05:00
|
|
|
const Runtime = require('../../src/engine/runtime');
|
2016-06-06 15:59:21 -04:00
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('spec', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-06 15:59:21 -04:00
|
|
|
|
|
|
|
t.type(Blocks, 'function');
|
|
|
|
t.type(b, 'object');
|
|
|
|
t.ok(b instanceof Blocks);
|
|
|
|
|
|
|
|
t.type(b._blocks, 'object');
|
2016-08-11 11:11:27 -04:00
|
|
|
t.type(b._scripts, 'object');
|
|
|
|
t.ok(Array.isArray(b._scripts));
|
2016-06-06 15:59:21 -04:00
|
|
|
|
|
|
|
t.type(b.createBlock, 'function');
|
|
|
|
t.type(b.moveBlock, 'function');
|
|
|
|
t.type(b.changeBlock, 'function');
|
|
|
|
t.type(b.deleteBlock, 'function');
|
2016-06-07 11:34:01 -04:00
|
|
|
t.type(b.getBlock, 'function');
|
2016-08-11 11:11:27 -04:00
|
|
|
t.type(b.getScripts, 'function');
|
2016-06-07 11:34:01 -04:00
|
|
|
t.type(b.getNextBlock, 'function');
|
2016-08-10 11:27:21 -04:00
|
|
|
t.type(b.getBranch, 'function');
|
2016-06-07 11:34:01 -04:00
|
|
|
t.type(b.getOpcode, 'function');
|
2019-06-11 18:31:34 -04:00
|
|
|
t.type(b.mutationToXML, 'function');
|
2020-05-22 06:00:43 -04:00
|
|
|
t.type(b.updateSensingOfReference, 'function');
|
2016-06-07 11:34:01 -04:00
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Getter tests
|
2017-04-20 19:17:05 -04:00
|
|
|
test('getBlock', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-07 11:34:01 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
2017-04-20 19:17:05 -04:00
|
|
|
const block = b.getBlock('foo');
|
2016-06-07 11:34:01 -04:00
|
|
|
t.type(block, 'object');
|
2017-04-20 19:17:05 -04:00
|
|
|
const notBlock = b.getBlock('?');
|
2016-06-07 11:34:01 -04:00
|
|
|
t.type(notBlock, 'undefined');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('getScripts', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2017-04-20 19:17:05 -04:00
|
|
|
let scripts = b.getScripts();
|
2016-08-11 11:11:27 -04:00
|
|
|
t.type(scripts, 'object');
|
|
|
|
t.equals(scripts.length, 0);
|
2016-06-07 11:34:01 -04:00
|
|
|
// Create two top-level blocks and one not.
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo2',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo3',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: false
|
|
|
|
});
|
|
|
|
|
2016-08-11 11:11:27 -04:00
|
|
|
scripts = b.getScripts();
|
|
|
|
t.type(scripts, 'object');
|
|
|
|
t.equals(scripts.length, 2);
|
|
|
|
t.ok(scripts.indexOf('foo') > -1);
|
|
|
|
t.ok(scripts.indexOf('foo2') > -1);
|
|
|
|
t.equals(scripts.indexOf('foo3'), -1);
|
2016-06-07 11:34:01 -04:00
|
|
|
t.end();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('getNextBlock', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-07 11:34:01 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
let next = b.getNextBlock('foo');
|
2016-06-07 11:34:01 -04:00
|
|
|
t.equals(next, null);
|
|
|
|
|
|
|
|
// Add a block with "foo" as its next.
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo2',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: 'foo',
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
|
|
|
|
next = b.getNextBlock('foo2');
|
|
|
|
t.equals(next, 'foo');
|
|
|
|
|
|
|
|
// Block that doesn't exist.
|
2017-04-20 19:17:05 -04:00
|
|
|
const noBlock = b.getNextBlock('?');
|
2016-06-07 11:34:01 -04:00
|
|
|
t.equals(noBlock, null);
|
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('getBranch', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-08-10 11:27:21 -04:00
|
|
|
// Single branch
|
2016-06-07 11:34:01 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {
|
|
|
|
SUBSTACK: {
|
|
|
|
name: 'SUBSTACK',
|
2016-09-06 10:55:52 -04:00
|
|
|
block: 'foo2',
|
|
|
|
shadow: null
|
2016-06-07 11:34:01 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo2',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: false
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
const branch = b.getBranch('foo');
|
2016-08-10 11:27:21 -04:00
|
|
|
t.equals(branch, 'foo2');
|
2016-06-07 11:34:01 -04:00
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
const notBranch = b.getBranch('?');
|
2016-08-10 11:27:21 -04:00
|
|
|
t.equals(notBranch, null);
|
2016-06-07 11:34:01 -04:00
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('getBranch2', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-08-10 11:27:21 -04:00
|
|
|
// Second branch
|
2016-06-07 11:34:01 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {
|
|
|
|
SUBSTACK: {
|
|
|
|
name: 'SUBSTACK',
|
2016-09-06 10:55:52 -04:00
|
|
|
block: 'foo2',
|
|
|
|
shadow: null
|
2016-06-07 11:34:01 -04:00
|
|
|
},
|
|
|
|
SUBSTACK2: {
|
|
|
|
name: 'SUBSTACK2',
|
2016-09-06 10:55:52 -04:00
|
|
|
block: 'foo3',
|
|
|
|
shadow: null
|
2016-06-07 11:34:01 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo2',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: false
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo3',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: false
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
const branch1 = b.getBranch('foo', 1);
|
|
|
|
const branch2 = b.getBranch('foo', 2);
|
2016-08-10 11:27:21 -04:00
|
|
|
t.equals(branch1, 'foo2');
|
|
|
|
t.equals(branch2, 'foo3');
|
2016-06-07 11:34:01 -04:00
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('getBranch with none', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-07 11:34:01 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
2017-04-20 19:17:05 -04:00
|
|
|
const noBranch = b.getBranch('foo');
|
2016-08-10 11:27:21 -04:00
|
|
|
t.equals(noBranch, null);
|
2016-06-07 11:34:01 -04:00
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('getOpcode', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2017-04-20 19:17:05 -04:00
|
|
|
const block = {
|
2016-06-07 11:34:01 -04:00
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
2017-03-22 04:48:30 -04:00
|
|
|
};
|
|
|
|
b.createBlock(block);
|
2017-04-20 19:17:05 -04:00
|
|
|
const opcode = b.getOpcode(block);
|
2016-06-07 11:34:01 -04:00
|
|
|
t.equals(opcode, 'TEST_BLOCK');
|
2017-04-20 19:17:05 -04:00
|
|
|
const undefinedBlock = b.getBlock('?');
|
|
|
|
const undefinedOpcode = b.getOpcode(undefinedBlock);
|
2017-03-22 04:48:30 -04:00
|
|
|
t.equals(undefinedOpcode, null);
|
2016-06-06 15:59:21 -04:00
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2019-06-11 18:31:34 -04:00
|
|
|
test('mutationToXML', t => {
|
|
|
|
const b = new Blocks(new Runtime());
|
|
|
|
const testStringRaw = '"arbitrary" & \'complicated\' test string';
|
|
|
|
const testStringEscaped = '\\"arbitrary\\" & 'complicated' test string';
|
|
|
|
const mutation = {
|
|
|
|
tagName: 'mutation',
|
|
|
|
children: [],
|
|
|
|
blockInfo: {
|
|
|
|
text: testStringRaw
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const xml = b.mutationToXML(mutation);
|
|
|
|
t.equals(
|
|
|
|
xml,
|
|
|
|
`<mutation blockInfo="{"text":"${testStringEscaped}"}"></mutation>`
|
|
|
|
);
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2016-06-07 11:34:01 -04:00
|
|
|
// Block events tests
|
2017-04-20 19:17:05 -04:00
|
|
|
test('create', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-06 15:59:21 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
|
2016-10-23 12:41:45 -04:00
|
|
|
t.type(b._blocks.foo, 'object');
|
|
|
|
t.equal(b._blocks.foo.opcode, 'TEST_BLOCK');
|
2016-08-11 11:11:27 -04:00
|
|
|
t.notEqual(b._scripts.indexOf('foo'), -1);
|
2016-06-06 15:59:21 -04:00
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('move', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-06 15:59:21 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'bar',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
|
|
|
|
// Attach 'bar' to the end of 'foo'
|
|
|
|
b.moveBlock({
|
|
|
|
id: 'bar',
|
|
|
|
newParent: 'foo'
|
|
|
|
});
|
2016-08-11 11:11:27 -04:00
|
|
|
t.equal(b._scripts.length, 1);
|
2016-06-06 15:59:21 -04:00
|
|
|
t.equal(Object.keys(b._blocks).length, 2);
|
2016-10-23 12:41:45 -04:00
|
|
|
t.equal(b._blocks.foo.next, 'bar');
|
2016-06-06 15:59:21 -04:00
|
|
|
|
|
|
|
// Detach 'bar' from 'foo'
|
|
|
|
b.moveBlock({
|
|
|
|
id: 'bar',
|
|
|
|
oldParent: 'foo'
|
|
|
|
});
|
2016-08-11 11:11:27 -04:00
|
|
|
t.equal(b._scripts.length, 2);
|
2016-06-06 15:59:21 -04:00
|
|
|
t.equal(Object.keys(b._blocks).length, 2);
|
2016-10-23 12:41:45 -04:00
|
|
|
t.equal(b._blocks.foo.next, null);
|
2016-06-06 15:59:21 -04:00
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('move into empty', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-09-08 09:40:01 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'bar',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.moveBlock({
|
|
|
|
id: 'bar',
|
|
|
|
newInput: 'fooInput',
|
|
|
|
newParent: 'foo'
|
|
|
|
});
|
2016-10-23 12:41:45 -04:00
|
|
|
t.equal(b._blocks.foo.inputs.fooInput.block, 'bar');
|
2016-09-08 09:40:01 -04:00
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('move no obscure shadow', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-09-08 09:40:01 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {
|
2016-10-24 11:02:19 -04:00
|
|
|
fooInput: {
|
2016-09-08 09:40:01 -04:00
|
|
|
name: 'fooInput',
|
|
|
|
block: 'x',
|
|
|
|
shadow: 'y'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'bar',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.moveBlock({
|
|
|
|
id: 'bar',
|
|
|
|
newInput: 'fooInput',
|
|
|
|
newParent: 'foo'
|
|
|
|
});
|
2016-10-23 12:41:45 -04:00
|
|
|
t.equal(b._blocks.foo.inputs.fooInput.block, 'bar');
|
|
|
|
t.equal(b._blocks.foo.inputs.fooInput.shadow, 'y');
|
2016-09-08 09:40:01 -04:00
|
|
|
t.end();
|
2019-03-11 14:52:40 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
test('move - attaching new shadow', t => {
|
|
|
|
const b = new Blocks(new Runtime());
|
|
|
|
// Block/shadow are null to mimic state right after a procedure_call block
|
|
|
|
// is mutated by adding an input. The "move" will attach the new shadow.
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {
|
|
|
|
fooInput: {
|
|
|
|
name: 'fooInput',
|
|
|
|
block: null,
|
|
|
|
shadow: null
|
|
|
|
}
|
|
|
|
},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'bar',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
shadow: true,
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.moveBlock({
|
|
|
|
id: 'bar',
|
|
|
|
newInput: 'fooInput',
|
|
|
|
newParent: 'foo'
|
|
|
|
});
|
|
|
|
t.equal(b._blocks.foo.inputs.fooInput.block, 'bar');
|
|
|
|
t.equal(b._blocks.foo.inputs.fooInput.shadow, 'bar');
|
|
|
|
t.end();
|
2016-09-08 09:40:01 -04:00
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('change', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-07 11:40:47 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {
|
|
|
|
someField: {
|
|
|
|
name: 'someField',
|
|
|
|
value: 'initial-value'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test that the field is updated
|
2016-10-23 12:41:45 -04:00
|
|
|
t.equal(b._blocks.foo.fields.someField.value, 'initial-value');
|
2016-06-07 11:40:47 -04:00
|
|
|
|
|
|
|
b.changeBlock({
|
|
|
|
element: 'field',
|
|
|
|
id: 'foo',
|
|
|
|
name: 'someField',
|
|
|
|
value: 'final-value'
|
|
|
|
});
|
|
|
|
|
2016-10-23 12:41:45 -04:00
|
|
|
t.equal(b._blocks.foo.fields.someField.value, 'final-value');
|
2016-06-07 11:40:47 -04:00
|
|
|
|
|
|
|
// Invalid cases
|
|
|
|
// No `element`
|
|
|
|
b.changeBlock({
|
|
|
|
id: 'foo',
|
|
|
|
name: 'someField',
|
|
|
|
value: 'invalid-value'
|
|
|
|
});
|
2016-10-23 12:41:45 -04:00
|
|
|
t.equal(b._blocks.foo.fields.someField.value, 'final-value');
|
2016-06-07 11:40:47 -04:00
|
|
|
|
|
|
|
// No block ID
|
|
|
|
b.changeBlock({
|
|
|
|
element: 'field',
|
|
|
|
name: 'someField',
|
|
|
|
value: 'invalid-value'
|
|
|
|
});
|
2016-10-23 12:41:45 -04:00
|
|
|
t.equal(b._blocks.foo.fields.someField.value, 'final-value');
|
2016-06-07 11:40:47 -04:00
|
|
|
|
|
|
|
// No such field
|
|
|
|
b.changeBlock({
|
|
|
|
element: 'field',
|
|
|
|
id: 'foo',
|
|
|
|
name: 'someWrongField',
|
|
|
|
value: 'final-value'
|
|
|
|
});
|
2016-10-23 12:41:45 -04:00
|
|
|
t.equal(b._blocks.foo.fields.someField.value, 'final-value');
|
2016-06-07 11:40:47 -04:00
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('delete', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-06 15:59:21 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
2017-11-15 11:34:20 -05:00
|
|
|
b.deleteBlock('foo');
|
2016-06-06 15:59:21 -04:00
|
|
|
|
2016-10-23 12:41:45 -04:00
|
|
|
t.type(b._blocks.foo, 'undefined');
|
2016-08-11 11:11:27 -04:00
|
|
|
t.equal(b._scripts.indexOf('foo'), -1);
|
2016-06-06 15:59:21 -04:00
|
|
|
t.end();
|
|
|
|
});
|
2016-06-07 11:11:20 -04:00
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('delete chain', t => {
|
2016-06-07 11:11:20 -04:00
|
|
|
// Create a chain of connected blocks and delete the top one.
|
|
|
|
// All of them should be deleted.
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-07 11:11:20 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: 'foo2',
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo2',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: 'foo3',
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: false
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo3',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: false
|
|
|
|
});
|
2017-11-15 11:34:20 -05:00
|
|
|
b.deleteBlock('foo');
|
2016-10-23 12:41:45 -04:00
|
|
|
t.type(b._blocks.foo, 'undefined');
|
|
|
|
t.type(b._blocks.foo2, 'undefined');
|
|
|
|
t.type(b._blocks.foo3, 'undefined');
|
2016-08-11 11:11:27 -04:00
|
|
|
t.equal(b._scripts.indexOf('foo'), -1);
|
2016-06-07 11:11:20 -04:00
|
|
|
t.equal(Object.keys(b._blocks).length, 0);
|
2016-08-11 11:11:27 -04:00
|
|
|
t.equal(b._scripts.length, 0);
|
2016-06-07 11:11:20 -04:00
|
|
|
t.end();
|
|
|
|
});
|
2016-06-07 11:18:41 -04:00
|
|
|
|
2017-04-20 19:17:05 -04:00
|
|
|
test('delete inputs', t => {
|
2016-06-07 11:18:41 -04:00
|
|
|
// Create a block with two inputs, one of which has its own input.
|
|
|
|
// Delete the block - all of them should be deleted.
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2016-06-07 11:18:41 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {
|
|
|
|
input1: {
|
|
|
|
name: 'input1',
|
2016-09-06 10:55:52 -04:00
|
|
|
block: 'foo2',
|
|
|
|
shadow: 'foo2'
|
2016-06-07 11:18:41 -04:00
|
|
|
},
|
|
|
|
SUBSTACK: {
|
|
|
|
name: 'SUBSTACK',
|
2016-09-06 10:55:52 -04:00
|
|
|
block: 'foo3',
|
|
|
|
shadow: null
|
2016-06-07 11:18:41 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
topLevel: true
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo2',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: false
|
|
|
|
});
|
2016-09-06 10:55:52 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo5',
|
|
|
|
opcode: 'TEST_OBSCURED_SHADOW',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: false
|
|
|
|
});
|
2016-06-07 11:18:41 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo3',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {
|
|
|
|
subinput: {
|
|
|
|
name: 'subinput',
|
2016-09-06 10:55:52 -04:00
|
|
|
block: 'foo4',
|
|
|
|
shadow: 'foo5'
|
2016-06-07 11:18:41 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
topLevel: false
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'foo4',
|
|
|
|
opcode: 'TEST_BLOCK',
|
|
|
|
next: null,
|
|
|
|
fields: {},
|
|
|
|
inputs: {},
|
|
|
|
topLevel: false
|
|
|
|
});
|
2017-11-15 11:34:20 -05:00
|
|
|
b.deleteBlock('foo');
|
2016-10-23 12:41:45 -04:00
|
|
|
t.type(b._blocks.foo, 'undefined');
|
|
|
|
t.type(b._blocks.foo2, 'undefined');
|
|
|
|
t.type(b._blocks.foo3, 'undefined');
|
|
|
|
t.type(b._blocks.foo4, 'undefined');
|
|
|
|
t.type(b._blocks.foo5, 'undefined');
|
2016-08-11 11:11:27 -04:00
|
|
|
t.equal(b._scripts.indexOf('foo'), -1);
|
2016-06-07 11:18:41 -04:00
|
|
|
t.equal(Object.keys(b._blocks).length, 0);
|
2016-08-11 11:11:27 -04:00
|
|
|
t.equal(b._scripts.length, 0);
|
2016-06-07 11:18:41 -04:00
|
|
|
t.end();
|
|
|
|
});
|
2018-02-09 17:29:41 -05:00
|
|
|
|
|
|
|
test('updateAssetName function updates name in sound field', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-02-09 17:29:41 -05:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
fields: {
|
|
|
|
SOUND_MENU: {
|
|
|
|
name: 'SOUND_MENU',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('foo').fields.SOUND_MENU.value, 'name1');
|
|
|
|
b.updateAssetName('name1', 'name2', 'sound');
|
|
|
|
t.equals(b.getBlock('foo').fields.SOUND_MENU.value, 'name2');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updateAssetName function updates name in costume field', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-02-09 17:29:41 -05:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
fields: {
|
|
|
|
COSTUME: {
|
|
|
|
name: 'COSTUME',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('foo').fields.COSTUME.value, 'name1');
|
|
|
|
b.updateAssetName('name1', 'name2', 'costume');
|
|
|
|
t.equals(b.getBlock('foo').fields.COSTUME.value, 'name2');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updateAssetName function updates name in backdrop field', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-02-09 17:29:41 -05:00
|
|
|
b.createBlock({
|
|
|
|
id: 'foo',
|
|
|
|
fields: {
|
|
|
|
BACKDROP: {
|
|
|
|
name: 'BACKDROP',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('foo').fields.BACKDROP.value, 'name1');
|
|
|
|
b.updateAssetName('name1', 'name2', 'backdrop');
|
|
|
|
t.equals(b.getBlock('foo').fields.BACKDROP.value, 'name2');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updateAssetName function updates name in all sprite fields', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-02-09 17:29:41 -05:00
|
|
|
b.createBlock({
|
|
|
|
id: 'id1',
|
|
|
|
fields: {
|
|
|
|
TOWARDS: {
|
|
|
|
name: 'TOWARDS',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id2',
|
|
|
|
fields: {
|
|
|
|
TO: {
|
|
|
|
name: 'TO',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id3',
|
|
|
|
fields: {
|
|
|
|
OBJECT: {
|
|
|
|
name: 'OBJECT',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id4',
|
|
|
|
fields: {
|
|
|
|
VIDEOONMENU2: {
|
|
|
|
name: 'VIDEOONMENU2',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id5',
|
|
|
|
fields: {
|
|
|
|
DISTANCETOMENU: {
|
|
|
|
name: 'DISTANCETOMENU',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id6',
|
|
|
|
fields: {
|
|
|
|
TOUCHINGOBJECTMENU: {
|
|
|
|
name: 'TOUCHINGOBJECTMENU',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id7',
|
|
|
|
fields: {
|
|
|
|
CLONE_OPTION: {
|
|
|
|
name: 'CLONE_OPTION',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('id1').fields.TOWARDS.value, 'name1');
|
|
|
|
t.equals(b.getBlock('id2').fields.TO.value, 'name1');
|
|
|
|
t.equals(b.getBlock('id3').fields.OBJECT.value, 'name1');
|
|
|
|
t.equals(b.getBlock('id4').fields.VIDEOONMENU2.value, 'name1');
|
|
|
|
t.equals(b.getBlock('id5').fields.DISTANCETOMENU.value, 'name1');
|
|
|
|
t.equals(b.getBlock('id6').fields.TOUCHINGOBJECTMENU.value, 'name1');
|
|
|
|
t.equals(b.getBlock('id7').fields.CLONE_OPTION.value, 'name1');
|
|
|
|
b.updateAssetName('name1', 'name2', 'sprite');
|
|
|
|
t.equals(b.getBlock('id1').fields.TOWARDS.value, 'name2');
|
|
|
|
t.equals(b.getBlock('id2').fields.TO.value, 'name2');
|
|
|
|
t.equals(b.getBlock('id3').fields.OBJECT.value, 'name2');
|
|
|
|
t.equals(b.getBlock('id4').fields.VIDEOONMENU2.value, 'name2');
|
|
|
|
t.equals(b.getBlock('id5').fields.DISTANCETOMENU.value, 'name2');
|
|
|
|
t.equals(b.getBlock('id6').fields.TOUCHINGOBJECTMENU.value, 'name2');
|
|
|
|
t.equals(b.getBlock('id7').fields.CLONE_OPTION.value, 'name2');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updateAssetName function updates name according to asset type', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-02-09 17:29:41 -05:00
|
|
|
b.createBlock({
|
|
|
|
id: 'id1',
|
|
|
|
fields: {
|
|
|
|
SOUND_MENU: {
|
|
|
|
name: 'SOUND_MENU',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id2',
|
|
|
|
fields: {
|
|
|
|
COSTUME: {
|
|
|
|
name: 'COSTUME',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('id1').fields.SOUND_MENU.value, 'name1');
|
|
|
|
t.equals(b.getBlock('id2').fields.COSTUME.value, 'name1');
|
|
|
|
b.updateAssetName('name1', 'name2', 'sound');
|
|
|
|
// only sound should get renamed
|
|
|
|
t.equals(b.getBlock('id1').fields.SOUND_MENU.value, 'name2');
|
|
|
|
t.equals(b.getBlock('id2').fields.COSTUME.value, 'name1');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updateAssetName only updates given name', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-02-09 17:29:41 -05:00
|
|
|
b.createBlock({
|
|
|
|
id: 'id1',
|
|
|
|
fields: {
|
|
|
|
COSTUME: {
|
|
|
|
name: 'COSTUME',
|
|
|
|
value: 'name1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id2',
|
|
|
|
fields: {
|
|
|
|
COSTUME: {
|
|
|
|
name: 'COSTUME',
|
|
|
|
value: 'foo'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('id1').fields.COSTUME.value, 'name1');
|
|
|
|
t.equals(b.getBlock('id2').fields.COSTUME.value, 'foo');
|
|
|
|
b.updateAssetName('name1', 'name2', 'costume');
|
|
|
|
t.equals(b.getBlock('id1').fields.COSTUME.value, 'name2');
|
|
|
|
t.equals(b.getBlock('id2').fields.COSTUME.value, 'foo');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updateAssetName doesn\'t update name if name isn\'t being used', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-02-09 17:29:41 -05:00
|
|
|
b.createBlock({
|
|
|
|
id: 'id1',
|
|
|
|
fields: {
|
|
|
|
BACKDROP: {
|
|
|
|
name: 'BACKDROP',
|
|
|
|
value: 'foo'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('id1').fields.BACKDROP.value, 'foo');
|
|
|
|
b.updateAssetName('name1', 'name2', 'backdrop');
|
|
|
|
t.equals(b.getBlock('id1').fields.BACKDROP.value, 'foo');
|
|
|
|
t.end();
|
|
|
|
});
|
2018-03-20 09:50:57 -04:00
|
|
|
|
2020-05-22 06:00:43 -04:00
|
|
|
test('updateSensingOfReference renames variables in sensing_of block', t => {
|
|
|
|
const b = new Blocks(new Runtime());
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id1',
|
|
|
|
opcode: 'sensing_of',
|
|
|
|
fields: {
|
|
|
|
PROPERTY: {
|
|
|
|
name: 'PROPERTY',
|
|
|
|
value: 'foo'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
inputs: {
|
|
|
|
OBJECT: {
|
|
|
|
name: 'OBJECT',
|
|
|
|
block: 'id2',
|
|
|
|
shadow: 'id2'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id2',
|
|
|
|
fields: {
|
|
|
|
OBJECT: {
|
|
|
|
name: 'OBJECT',
|
|
|
|
value: '_stage_'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('id1').fields.PROPERTY.value, 'foo');
|
|
|
|
b.updateSensingOfReference('foo', 'bar', '_stage_');
|
|
|
|
t.equals(b.getBlock('id1').fields.PROPERTY.value, 'bar');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updateSensingOfReference doesn\'t rename if block is inserted', t => {
|
|
|
|
const b = new Blocks(new Runtime());
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id1',
|
|
|
|
opcode: 'sensing_of',
|
|
|
|
fields: {
|
|
|
|
PROPERTY: {
|
|
|
|
name: 'PROPERTY',
|
|
|
|
value: 'foo'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
inputs: {
|
|
|
|
OBJECT: {
|
|
|
|
name: 'OBJECT',
|
|
|
|
block: 'id3',
|
|
|
|
shadow: 'id2'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id2',
|
|
|
|
fields: {
|
|
|
|
OBJECT: {
|
|
|
|
name: 'OBJECT',
|
|
|
|
value: '_stage_'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id3',
|
|
|
|
opcode: 'answer'
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('id1').fields.PROPERTY.value, 'foo');
|
|
|
|
b.updateSensingOfReference('foo', 'bar', '_stage_');
|
|
|
|
t.equals(b.getBlock('id1').fields.PROPERTY.value, 'foo');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updateSensingOfReference doesn\'t rename if name is not being used', t => {
|
|
|
|
const b = new Blocks(new Runtime());
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id1',
|
|
|
|
opcode: 'sensing_of',
|
|
|
|
fields: {
|
|
|
|
PROPERTY: {
|
|
|
|
name: 'PROPERTY',
|
|
|
|
value: 'foo'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
inputs: {
|
|
|
|
OBJECT: {
|
|
|
|
name: 'OBJECT',
|
|
|
|
block: 'id2',
|
|
|
|
shadow: 'id2'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id2',
|
|
|
|
fields: {
|
|
|
|
OBJECT: {
|
|
|
|
name: 'OBJECT',
|
|
|
|
value: '_stage_'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('id1').fields.PROPERTY.value, 'foo');
|
|
|
|
b.updateSensingOfReference('meow', 'meow2', '_stage_');
|
|
|
|
t.equals(b.getBlock('id1').fields.PROPERTY.value, 'foo');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('updateSensingOfReference doesn\'t rename other targets\' variables', t => {
|
|
|
|
const b = new Blocks(new Runtime());
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id1',
|
|
|
|
opcode: 'sensing_of',
|
|
|
|
fields: {
|
|
|
|
PROPERTY: {
|
|
|
|
name: 'PROPERTY',
|
|
|
|
value: 'foo'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
inputs: {
|
|
|
|
OBJECT: {
|
|
|
|
name: 'OBJECT',
|
|
|
|
block: 'id2',
|
|
|
|
shadow: 'id2'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'id2',
|
|
|
|
fields: {
|
|
|
|
OBJECT: {
|
|
|
|
name: 'OBJECT',
|
|
|
|
value: '_stage_'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
t.equals(b.getBlock('id1').fields.PROPERTY.value, 'foo');
|
|
|
|
b.updateSensingOfReference('foo', 'bar', 'Cat');
|
|
|
|
t.equals(b.getBlock('id1').fields.PROPERTY.value, 'foo');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
2018-03-20 09:50:57 -04:00
|
|
|
test('updateTargetSpecificBlocks changes sprite clicked hat to stage clicked for stage', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-03-20 09:50:57 -04:00
|
|
|
b.createBlock({
|
|
|
|
id: 'originallySpriteClicked',
|
|
|
|
opcode: 'event_whenthisspriteclicked'
|
|
|
|
});
|
|
|
|
b.createBlock({
|
|
|
|
id: 'originallyStageClicked',
|
|
|
|
opcode: 'event_whenstageclicked'
|
|
|
|
});
|
|
|
|
|
|
|
|
// originallySpriteClicked does not update when on a non-stage target
|
|
|
|
b.updateTargetSpecificBlocks(false /* isStage */);
|
|
|
|
t.equals(b.getBlock('originallySpriteClicked').opcode, 'event_whenthisspriteclicked');
|
|
|
|
|
|
|
|
// originallySpriteClicked does update when on a stage target
|
|
|
|
b.updateTargetSpecificBlocks(true /* isStage */);
|
|
|
|
t.equals(b.getBlock('originallySpriteClicked').opcode, 'event_whenstageclicked');
|
|
|
|
|
|
|
|
// originallyStageClicked does not update when on a stage target
|
|
|
|
b.updateTargetSpecificBlocks(true /* isStage */);
|
|
|
|
t.equals(b.getBlock('originallyStageClicked').opcode, 'event_whenstageclicked');
|
|
|
|
|
|
|
|
// originallyStageClicked does update when on a non-stage target
|
|
|
|
b.updateTargetSpecificBlocks(false/* isStage */);
|
|
|
|
t.equals(b.getBlock('originallyStageClicked').opcode, 'event_whenthisspriteclicked');
|
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
2018-06-20 10:32:36 -04:00
|
|
|
|
|
|
|
test('getAllVariableAndListReferences returns an empty map references when variable blocks do not exist', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-06-20 10:32:36 -04:00
|
|
|
t.equal(Object.keys(b.getAllVariableAndListReferences()).length, 0);
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('getAllVariableAndListReferences returns references when variable blocks exist', t => {
|
2019-01-28 19:30:42 -05:00
|
|
|
const b = new Blocks(new Runtime());
|
2018-06-20 10:32:36 -04:00
|
|
|
|
|
|
|
let varListRefs = b.getAllVariableAndListReferences();
|
|
|
|
t.equal(Object.keys(varListRefs).length, 0);
|
|
|
|
|
|
|
|
b.createBlock(adapter(events.mockVariableBlock)[0]);
|
|
|
|
b.createBlock(adapter(events.mockListBlock)[0]);
|
|
|
|
|
|
|
|
varListRefs = b.getAllVariableAndListReferences();
|
|
|
|
t.equal(Object.keys(varListRefs).length, 2);
|
|
|
|
t.equal(Array.isArray(varListRefs['mock var id']), true);
|
|
|
|
t.equal(varListRefs['mock var id'].length, 1);
|
|
|
|
t.equal(varListRefs['mock var id'][0].type, Variable.SCALAR_TYPE);
|
|
|
|
t.equal(varListRefs['mock var id'][0].referencingField.value, 'a mock variable');
|
|
|
|
t.equal(Array.isArray(varListRefs['mock list id']), true);
|
|
|
|
t.equal(varListRefs['mock list id'].length, 1);
|
|
|
|
t.equal(varListRefs['mock list id'][0].type, Variable.LIST_TYPE);
|
|
|
|
t.equal(varListRefs['mock list id'][0].referencingField.value, 'a mock list');
|
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
2019-02-06 16:58:46 -05:00
|
|
|
|
|
|
|
test('getAllVariableAndListReferences does not return broadcast blocks if the flag is left out', t => {
|
|
|
|
const b = new Blocks(new Runtime());
|
|
|
|
b.createBlock(adapter(events.mockBroadcastBlock)[0]);
|
|
|
|
b.createBlock(adapter(events.mockBroadcastBlock)[1]);
|
|
|
|
|
|
|
|
t.equal(Object.keys(b.getAllVariableAndListReferences()).length, 0);
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
|
|
|
|
test('getAllVariableAndListReferences returns broadcast when we tell it to', t => {
|
|
|
|
const b = new Blocks(new Runtime());
|
|
|
|
|
|
|
|
b.createBlock(adapter(events.mockVariableBlock)[0]);
|
|
|
|
// Make the broadcast block and its shadow (which includes the actual broadcast field).
|
|
|
|
b.createBlock(adapter(events.mockBroadcastBlock)[0]);
|
|
|
|
b.createBlock(adapter(events.mockBroadcastBlock)[1]);
|
|
|
|
|
|
|
|
const varListRefs = b.getAllVariableAndListReferences(null, true);
|
|
|
|
|
|
|
|
t.equal(Object.keys(varListRefs).length, 2);
|
|
|
|
t.equal(Array.isArray(varListRefs['mock var id']), true);
|
|
|
|
t.equal(varListRefs['mock var id'].length, 1);
|
|
|
|
t.equal(varListRefs['mock var id'][0].type, Variable.SCALAR_TYPE);
|
|
|
|
t.equal(varListRefs['mock var id'][0].referencingField.value, 'a mock variable');
|
|
|
|
t.equal(Array.isArray(varListRefs['mock broadcast message id']), true);
|
|
|
|
t.equal(varListRefs['mock broadcast message id'].length, 1);
|
|
|
|
t.equal(varListRefs['mock broadcast message id'][0].type, Variable.BROADCAST_MESSAGE_TYPE);
|
|
|
|
t.equal(varListRefs['mock broadcast message id'][0].referencingField.value, 'my message');
|
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|