Merge pull request #829 from kchadha/broadcast-message-typed-variable

Broadcast message functionality
This commit is contained in:
Paul Kaplan 2017-12-01 11:51:38 -05:00 committed by GitHub
commit a9e95f3b01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 164 additions and 39 deletions

View file

@ -30,24 +30,28 @@ class Scratch3DataBlocks {
} }
getVariable (args, util) { getVariable (args, util) {
const variable = util.target.lookupOrCreateVariable(args.VARIABLE); const variable = util.target.lookupOrCreateVariable(
args.VARIABLE.id, args.VARIABLE.name);
return variable.value; return variable.value;
} }
setVariableTo (args, util) { setVariableTo (args, util) {
const variable = util.target.lookupOrCreateVariable(args.VARIABLE); const variable = util.target.lookupOrCreateVariable(
args.VARIABLE.id, args.VARIABLE.name);
variable.value = args.VALUE; variable.value = args.VALUE;
} }
changeVariableBy (args, util) { changeVariableBy (args, util) {
const variable = util.target.lookupOrCreateVariable(args.VARIABLE); const variable = util.target.lookupOrCreateVariable(
args.VARIABLE.id, args.VARIABLE.name);
const castedValue = Cast.toNumber(variable.value); const castedValue = Cast.toNumber(variable.value);
const dValue = Cast.toNumber(args.VALUE); const dValue = Cast.toNumber(args.VALUE);
variable.value = castedValue + dValue; variable.value = castedValue + dValue;
} }
getListContents (args, util) { getListContents (args, util) {
const list = util.target.lookupOrCreateList(args.LIST); const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);
// Determine if the list is all single letters. // Determine if the list is all single letters.
// If it is, report contents joined together with no separator. // If it is, report contents joined together with no separator.
// If it's not, report contents joined together with a space. // If it's not, report contents joined together with a space.
@ -68,12 +72,14 @@ class Scratch3DataBlocks {
} }
addToList (args, util) { addToList (args, util) {
const list = util.target.lookupOrCreateList(args.LIST); const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);
list.value.push(args.ITEM); list.value.push(args.ITEM);
} }
deleteOfList (args, util) { deleteOfList (args, util) {
const list = util.target.lookupOrCreateList(args.LIST); const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);
const index = Cast.toListIndex(args.INDEX, list.value.length); const index = Cast.toListIndex(args.INDEX, list.value.length);
if (index === Cast.LIST_INVALID) { if (index === Cast.LIST_INVALID) {
return; return;
@ -86,7 +92,8 @@ class Scratch3DataBlocks {
insertAtList (args, util) { insertAtList (args, util) {
const item = args.ITEM; const item = args.ITEM;
const list = util.target.lookupOrCreateList(args.LIST); const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);
const index = Cast.toListIndex(args.INDEX, list.value.length + 1); const index = Cast.toListIndex(args.INDEX, list.value.length + 1);
if (index === Cast.LIST_INVALID) { if (index === Cast.LIST_INVALID) {
return; return;
@ -96,7 +103,8 @@ class Scratch3DataBlocks {
replaceItemOfList (args, util) { replaceItemOfList (args, util) {
const item = args.ITEM; const item = args.ITEM;
const list = util.target.lookupOrCreateList(args.LIST); const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);
const index = Cast.toListIndex(args.INDEX, list.value.length); const index = Cast.toListIndex(args.INDEX, list.value.length);
if (index === Cast.LIST_INVALID) { if (index === Cast.LIST_INVALID) {
return; return;
@ -105,7 +113,8 @@ class Scratch3DataBlocks {
} }
getItemOfList (args, util) { getItemOfList (args, util) {
const list = util.target.lookupOrCreateList(args.LIST); const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);
const index = Cast.toListIndex(args.INDEX, list.value.length); const index = Cast.toListIndex(args.INDEX, list.value.length);
if (index === Cast.LIST_INVALID) { if (index === Cast.LIST_INVALID) {
return ''; return '';
@ -114,13 +123,15 @@ class Scratch3DataBlocks {
} }
lengthOfList (args, util) { lengthOfList (args, util) {
const list = util.target.lookupOrCreateList(args.LIST); const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);
return list.value.length; return list.value.length;
} }
listContainsItem (args, util) { listContainsItem (args, util) {
const item = args.ITEM; const item = args.ITEM;
const list = util.target.lookupOrCreateList(args.LIST); const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);
if (list.value.indexOf(item) >= 0) { if (list.value.indexOf(item) >= 0) {
return true; return true;
} }

View file

@ -56,14 +56,18 @@ class Scratch3EventBlocks {
} }
broadcast (args, util) { broadcast (args, util) {
const broadcastOption = Cast.toString(args.BROADCAST_OPTION); const broadcastVar = util.runtime.getTargetForStage().lookupOrCreateBroadcastMsg(
args.BROADCAST_OPTION.id, args.BROADCAST_OPTION.name);
const broadcastOption = broadcastVar.name;
util.startHats('event_whenbroadcastreceived', { util.startHats('event_whenbroadcastreceived', {
BROADCAST_OPTION: broadcastOption BROADCAST_OPTION: broadcastOption
}); });
} }
broadcastAndWait (args, util) { broadcastAndWait (args, util) {
const broadcastOption = Cast.toString(args.BROADCAST_OPTION); const broadcastVar = util.runtime.getTargetForStage().lookupOrCreateBroadcastMsg(
args.BROADCAST_OPTION.id, args.BROADCAST_OPTION.name);
const broadcastOption = broadcastVar.name;
// Have we run before, starting threads? // Have we run before, starting threads?
if (!util.stackFrame.startedThreads) { if (!util.stackFrame.startedThreads) {
// No - start hats for this broadcast. // No - start hats for this broadcast.

View file

@ -304,7 +304,14 @@ class Blocks {
// Check if this variable exists on the current target or stage. // Check if this variable exists on the current target or stage.
// If not, create it on the stage. // If not, create it on the stage.
// TODO create global and local variables when UI provides a way. // TODO create global and local variables when UI provides a way.
if (!optRuntime.getEditingTarget().lookupVariableById(e.varId)) { if (optRuntime.getEditingTarget()) {
if (!optRuntime.getEditingTarget().lookupVariableById(e.varId)) {
stage.createVariable(e.varId, e.varName, e.varType);
}
} else if (!stage.lookupVariableById(e.varId)) {
// Since getEditingTarget returned null, we now need to
// explicitly check if the stage has the variable, and
// create one if not.
stage.createVariable(e.varId, e.varName, e.varType); stage.createVariable(e.varId, e.varName, e.varType);
} }
break; break;
@ -365,7 +372,8 @@ class Blocks {
case 'field': case 'field':
// Update block value // Update block value
if (!block.fields[args.name]) return; if (!block.fields[args.name]) return;
if (args.name === 'VARIABLE' || args.name === 'LIST') { if (args.name === 'VARIABLE' || args.name === 'LIST' ||
args.name === 'BROADCAST_OPTION') {
// Get variable name using the id in args.value. // Get variable name using the id in args.value.
const variable = optRuntime.getEditingTarget().lookupVariableById(args.value); const variable = optRuntime.getEditingTarget().lookupVariableById(args.value);
if (variable) { if (variable) {

View file

@ -175,8 +175,12 @@ const execute = function (sequencer, thread) {
// Add all fields on this block to the argValues. // Add all fields on this block to the argValues.
for (const fieldName in fields) { for (const fieldName in fields) {
if (!fields.hasOwnProperty(fieldName)) continue; if (!fields.hasOwnProperty(fieldName)) continue;
if (fieldName === 'VARIABLE' || fieldName === 'LIST') { if (fieldName === 'VARIABLE' || fieldName === 'LIST' ||
argValues[fieldName] = fields[fieldName].id; fieldName === 'BROADCAST_OPTION') {
argValues[fieldName] = {
id: fields[fieldName].id,
name: fields[fieldName].value
};
} else { } else {
argValues[fieldName] = fields[fieldName].value; argValues[fieldName] = fields[fieldName].value;
} }

View file

@ -92,6 +92,22 @@ class Target extends EventEmitter {
return newVariable; return newVariable;
} }
/**
* Look up a broadcast message object, and create it if one doesn't exist.
* @param {string} id Id of the variable.
* @param {string} name Name of the variable.
* @return {!Variable} Variable object.
*/
lookupOrCreateBroadcastMsg (id, name) {
const broadcastMsg = this.lookupVariableById(id);
if (broadcastMsg) return broadcastMsg;
// No variable with this name exists - create it locally.
const newBroadcastMsg = new Variable(id, name,
Variable.BROADCAST_MESSAGE_TYPE, false);
this.variables[id] = newBroadcastMsg;
return newBroadcastMsg;
}
/** /**
* Look up a variable object. * Look up a variable object.
* Search begins for local variables; then look for globals. * Search begins for local variables; then look for globals.
@ -134,7 +150,7 @@ class Target extends EventEmitter {
* dictionary of variables. * dictionary of variables.
* @param {string} id Id of variable * @param {string} id Id of variable
* @param {string} name Name of variable. * @param {string} name Name of variable.
* @param {string} type Type of variable, '' or 'list' * @param {string} type Type of variable, '', 'broadcast_msg', or 'list'
*/ */
createVariable (id, name, type) { createVariable (id, name, type) {
if (!this.variables.hasOwnProperty(id)) { if (!this.variables.hasOwnProperty(id)) {

View file

@ -25,6 +25,9 @@ class Variable {
case Variable.LIST_TYPE: case Variable.LIST_TYPE:
this.value = []; this.value = [];
break; break;
case Variable.BROADCAST_MESSAGE_TYPE:
this.value = this.name;
break;
default: default:
throw new Error(`Invalid variable type: ${this.type}`); throw new Error(`Invalid variable type: ${this.type}`);
} }
@ -51,6 +54,14 @@ class Variable {
static get LIST_TYPE () { static get LIST_TYPE () {
return 'list'; return 'list';
} }
/**
* Type representation for list variables.
* @const {string}
*/
static get BROADCAST_MESSAGE_TYPE () {
return 'broadcast_msg';
}
} }
module.exports = Variable; module.exports = Variable;

View file

@ -88,17 +88,18 @@ const flatten = function (blocks) {
* a list of blocks in a branch (e.g., in forever), * a list of blocks in a branch (e.g., in forever),
* or a list of blocks in an argument (e.g., move [pick random...]). * or a list of blocks in an argument (e.g., move [pick random...]).
* @param {Array.<object>} blockList SB2 JSON-format block list. * @param {Array.<object>} blockList SB2 JSON-format block list.
* @param {Function} addBroadcastMsg function to update broadcast message name map
* @param {Function} getVariableId function to retreive a variable's ID based on name * @param {Function} getVariableId function to retreive a variable's ID based on name
* @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here. * @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here.
* @return {Array.<object>} Scratch VM-format block list. * @return {Array.<object>} Scratch VM-format block list.
*/ */
const parseBlockList = function (blockList, getVariableId, extensions) { const parseBlockList = function (blockList, addBroadcastMsg, getVariableId, extensions) {
const resultingList = []; const resultingList = [];
let previousBlock = null; // For setting next. let previousBlock = null; // For setting next.
for (let i = 0; i < blockList.length; i++) { for (let i = 0; i < blockList.length; i++) {
const block = blockList[i]; const block = blockList[i];
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
const parsedBlock = parseBlock(block, getVariableId, extensions); const parsedBlock = parseBlock(block, addBroadcastMsg, getVariableId, extensions);
if (typeof parsedBlock === 'undefined') continue; if (typeof parsedBlock === 'undefined') continue;
if (previousBlock) { if (previousBlock) {
parsedBlock.parent = previousBlock.id; parsedBlock.parent = previousBlock.id;
@ -115,16 +116,17 @@ const parseBlockList = function (blockList, getVariableId, extensions) {
* This should only handle top-level scripts that include X, Y coordinates. * This should only handle top-level scripts that include X, Y coordinates.
* @param {!object} scripts Scripts object from SB2 JSON. * @param {!object} scripts Scripts object from SB2 JSON.
* @param {!Blocks} blocks Blocks object to load parsed blocks into. * @param {!Blocks} blocks Blocks object to load parsed blocks into.
* @param {Function} addBroadcastMsg function to update broadcast message name map
* @param {Function} getVariableId function to retreive a variable's ID based on name * @param {Function} getVariableId function to retreive a variable's ID based on name
* @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here. * @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here.
*/ */
const parseScripts = function (scripts, blocks, getVariableId, extensions) { const parseScripts = function (scripts, blocks, addBroadcastMsg, getVariableId, extensions) {
for (let i = 0; i < scripts.length; i++) { for (let i = 0; i < scripts.length; i++) {
const script = scripts[i]; const script = scripts[i];
const scriptX = script[0]; const scriptX = script[0];
const scriptY = script[1]; const scriptY = script[1];
const blockList = script[2]; const blockList = script[2];
const parsedBlockList = parseBlockList(blockList, getVariableId, extensions); const parsedBlockList = parseBlockList(blockList, addBroadcastMsg, getVariableId, extensions);
if (parsedBlockList[0]) { if (parsedBlockList[0]) {
// Adjust script coordinates to account for // Adjust script coordinates to account for
// larger block size in scratch-blocks. // larger block size in scratch-blocks.
@ -166,6 +168,20 @@ const generateVariableIdGetter = (function () {
}; };
}()); }());
const globalBroadcastMsgStateGenerator = (function () {
let broadcastMsgNameMap = {};
return function (topLevel) {
if (topLevel) broadcastMsgNameMap = {};
return {
broadcastMsgMapUpdater: function (name) {
broadcastMsgNameMap[name] = `broadcastMsgId-${name}`;
return broadcastMsgNameMap[name];
},
globalBroadcastMsgs: broadcastMsgNameMap
};
};
}());
/** /**
* Parse a single "Scratch object" and create all its in-memory VM objects. * Parse a single "Scratch object" and create all its in-memory VM objects.
* TODO: parse the "info" section, especially "savedExtensions" * TODO: parse the "info" section, especially "savedExtensions"
@ -227,6 +243,9 @@ const parseScratchObject = function (object, runtime, extensions, topLevel) {
const getVariableId = generateVariableIdGetter(target.id, topLevel); const getVariableId = generateVariableIdGetter(target.id, topLevel);
const globalBroadcastMsgObj = globalBroadcastMsgStateGenerator(topLevel);
const addBroadcastMsg = globalBroadcastMsgObj.broadcastMsgMapUpdater;
// Load target properties from JSON. // Load target properties from JSON.
if (object.hasOwnProperty('variables')) { if (object.hasOwnProperty('variables')) {
for (let j = 0; j < object.variables.length; j++) { for (let j = 0; j < object.variables.length; j++) {
@ -244,7 +263,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel) {
// If included, parse any and all scripts/blocks on the object. // If included, parse any and all scripts/blocks on the object.
if (object.hasOwnProperty('scripts')) { if (object.hasOwnProperty('scripts')) {
parseScripts(object.scripts, blocks, getVariableId, extensions); parseScripts(object.scripts, blocks, addBroadcastMsg, getVariableId, extensions);
} }
if (object.hasOwnProperty('lists')) { if (object.hasOwnProperty('lists')) {
@ -317,6 +336,21 @@ const parseScratchObject = function (object, runtime, extensions, topLevel) {
Promise.all( Promise.all(
childrenPromises childrenPromises
).then(children => { ).then(children => {
// Need create broadcast msgs as variables after
// all other targets have finished processing.
if (target.isStage) {
const allBroadcastMsgs = globalBroadcastMsgObj.globalBroadcastMsgs;
for (const msgName in allBroadcastMsgs) {
const msgId = allBroadcastMsgs[msgName];
const newMsg = new Variable(
msgId,
msgName,
Variable.BROADCAST_MESSAGE_TYPE,
false
);
target.variables[newMsg.id] = newMsg;
}
}
let targets = [target]; let targets = [target];
for (let n = 0; n < children.length; n++) { for (let n = 0; n < children.length; n++) {
targets = targets.concat(children[n]); targets = targets.concat(children[n]);
@ -349,11 +383,12 @@ const sb2import = function (json, runtime, optForceSprite) {
/** /**
* Parse a single SB2 JSON-formatted block and its children. * Parse a single SB2 JSON-formatted block and its children.
* @param {!object} sb2block SB2 JSON-formatted block. * @param {!object} sb2block SB2 JSON-formatted block.
* @param {Function} addBroadcastMsg function to update broadcast message name map
* @param {Function} getVariableId function to retrieve a variable's ID based on name * @param {Function} getVariableId function to retrieve a variable's ID based on name
* @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here. * @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here.
* @return {object} Scratch VM format block, or null if unsupported object. * @return {object} Scratch VM format block, or null if unsupported object.
*/ */
const parseBlock = function (sb2block, getVariableId, extensions) { const parseBlock = function (sb2block, addBroadcastMsg, getVariableId, extensions) {
// First item in block object is the old opcode (e.g., 'forward:'). // First item in block object is the old opcode (e.g., 'forward:').
const oldOpcode = sb2block[0]; const oldOpcode = sb2block[0];
// Convert the block using the specMap. See sb2specmap.js. // Convert the block using the specMap. See sb2specmap.js.
@ -404,10 +439,10 @@ const parseBlock = function (sb2block, getVariableId, extensions) {
let innerBlocks; let innerBlocks;
if (typeof providedArg[0] === 'object' && providedArg[0]) { if (typeof providedArg[0] === 'object' && providedArg[0]) {
// Block list occupies the input. // Block list occupies the input.
innerBlocks = parseBlockList(providedArg, getVariableId, extensions); innerBlocks = parseBlockList(providedArg, addBroadcastMsg, getVariableId, extensions);
} else { } else {
// Single block occupies the input. // Single block occupies the input.
innerBlocks = [parseBlock(providedArg, getVariableId, extensions)]; innerBlocks = [parseBlock(providedArg, addBroadcastMsg, getVariableId, extensions)];
} }
let previousBlock = null; let previousBlock = null;
for (let j = 0; j < innerBlocks.length; j++) { for (let j = 0; j < innerBlocks.length; j++) {
@ -493,6 +528,10 @@ const parseBlock = function (sb2block, getVariableId, extensions) {
if (expectedArg.fieldName === 'VARIABLE' || expectedArg.fieldName === 'LIST') { if (expectedArg.fieldName === 'VARIABLE' || expectedArg.fieldName === 'LIST') {
// Add `id` property to variable fields // Add `id` property to variable fields
activeBlock.fields[expectedArg.fieldName].id = getVariableId(providedArg); activeBlock.fields[expectedArg.fieldName].id = getVariableId(providedArg);
} else if (expectedArg.fieldName === 'BROADCAST_OPTION') {
// add the name in this field to the broadcast msg name map
const broadcastId = addBroadcastMsg(providedArg);
activeBlock.fields[expectedArg.fieldName].id = broadcastId;
} }
const varType = expectedArg.variableType; const varType = expectedArg.variableType;
if (typeof varType === 'string') { if (typeof varType === 'string') {

View file

@ -656,7 +656,8 @@ const specMap = {
argMap: [ argMap: [
{ {
type: 'field', type: 'field',
fieldName: 'BROADCAST_OPTION' fieldName: 'BROADCAST_OPTION',
variableType: Variable.BROADCAST_MESSAGE_TYPE
} }
] ]
}, },
@ -664,9 +665,9 @@ const specMap = {
opcode: 'event_broadcast', opcode: 'event_broadcast',
argMap: [ argMap: [
{ {
type: 'input', type: 'field',
inputOp: 'event_broadcast_menu', fieldName: 'BROADCAST_OPTION',
inputName: 'BROADCAST_OPTION' variableType: Variable.BROADCAST_MESSAGE_TYPE
} }
] ]
}, },
@ -674,9 +675,9 @@ const specMap = {
opcode: 'event_broadcastandwait', opcode: 'event_broadcastandwait',
argMap: [ argMap: [
{ {
type: 'input', type: 'field',
inputOp: 'event_broadcast_menu', fieldName: 'BROADCAST_OPTION',
inputName: 'BROADCAST_OPTION' variableType: Variable.BROADCAST_MESSAGE_TYPE
} }
] ]
}, },

View file

@ -12,7 +12,7 @@ test('#760 - broadcastAndWait', t => {
id: 'broadcastAndWaitBlock', id: 'broadcastAndWaitBlock',
fields: { fields: {
BROADCAST_OPTION: { BROADCAST_OPTION: {
id: 'BROADCAST_OPTION', id: 'testBroadcastID',
value: 'message' value: 'message'
} }
}, },
@ -30,7 +30,7 @@ test('#760 - broadcastAndWait', t => {
id: 'receiveMessageBlock', id: 'receiveMessageBlock',
fields: { fields: {
BROADCAST_OPTION: { BROADCAST_OPTION: {
id: 'BROADCAST_OPTION', id: 'testBroadcastID',
value: 'message' value: 'message'
} }
}, },
@ -51,15 +51,17 @@ test('#760 - broadcastAndWait', t => {
b.createBlock(broadcastAndWaitBlock); b.createBlock(broadcastAndWaitBlock);
b.createBlock(receiveMessageBlock); b.createBlock(receiveMessageBlock);
const tgt = new Target(rt, b); const tgt = new Target(rt, b);
tgt.isStage = true;
rt.targets.push(tgt); rt.targets.push(tgt);
let th = rt._pushThread('broadcastAndWaitBlock', t); let th = rt._pushThread('broadcastAndWaitBlock', t);
const util = new BlockUtility(); const util = new BlockUtility();
util.sequencer = rt.sequencer; util.sequencer = rt.sequencer;
util.thread = th; util.thread = th;
util.runtime = rt;
// creates threads // creates threads
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util); e.broadcastAndWait({BROADCAST_OPTION: {id: 'testBroadcastID', name: 'message'}}, util);
t.strictEqual(rt.threads.length, 2); t.strictEqual(rt.threads.length, 2);
t.strictEqual(rt.threads[1].topBlock, 'receiveMessageBlock'); t.strictEqual(rt.threads[1].topBlock, 'receiveMessageBlock');
// yields when some thread is active // yields when some thread is active
@ -76,18 +78,18 @@ test('#760 - broadcastAndWait', t => {
// restarts done threads that are in runtime threads // restarts done threads that are in runtime threads
th = rt._pushThread('broadcastAndWaitBlock', tgt); th = rt._pushThread('broadcastAndWaitBlock', tgt);
util.thread = th; util.thread = th;
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util); e.broadcastAndWait({BROADCAST_OPTION: {id: 'testBroadcastID', name: 'message'}}, util);
t.strictEqual(rt.threads.length, 3); t.strictEqual(rt.threads.length, 3);
t.strictEqual(rt.threads[1].status, Thread.STATUS_RUNNING); t.strictEqual(rt.threads[1].status, Thread.STATUS_RUNNING);
t.strictEqual(th.status, Thread.STATUS_YIELD); t.strictEqual(th.status, Thread.STATUS_YIELD);
// yields when some restarted thread is active // yields when some restarted thread is active
th.status = Thread.STATUS_RUNNING; th.status = Thread.STATUS_RUNNING;
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util); e.broadcastAndWait({BROADCAST_OPTION: {id: 'testBroadcastID', name: 'message'}}, util);
t.strictEqual(th.status, Thread.STATUS_YIELD); t.strictEqual(th.status, Thread.STATUS_YIELD);
// does not yield once all threads are done // does not yield once all threads are done
th.status = Thread.STATUS_RUNNING; th.status = Thread.STATUS_RUNNING;
rt.threads[1].status = Thread.STATUS_DONE; rt.threads[1].status = Thread.STATUS_DONE;
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util); e.broadcastAndWait({BROADCAST_OPTION: {id: 'testBroadcastID', name: 'message'}}, util);
t.strictEqual(th.status, Thread.STATUS_RUNNING); t.strictEqual(th.status, Thread.STATUS_RUNNING);
t.end(); t.end();

View file

@ -173,3 +173,32 @@ test('lookupOrCreateList returns list if one with given id exists', t => {
t.end(); t.end();
}); });
test('lookupOrCreateBroadcastMsg creates a var if one does not exist', t => {
const target = new Target();
const variables = target.variables;
t.equal(Object.keys(variables).length, 0);
const broadcastVar = target.lookupOrCreateBroadcastMsg('foo', 'bar');
t.equal(Object.keys(variables).length, 1);
t.equal(broadcastVar.id, 'foo');
t.equal(broadcastVar.name, 'bar');
t.end();
});
test('lookupOrCreateBroadcastMsg returns the var with given id if exists', t => {
const target = new Target();
const variables = target.variables;
t.equal(Object.keys(variables).length, 0);
target.createVariable('foo', 'bar', Variable.BROADCAST_MESSAGE_TYPE);
t.equal(Object.keys(variables).length, 1);
const broadcastMsg = target.lookupOrCreateBroadcastMsg('foo', 'bar');
t.equal(Object.keys(variables).length, 1);
t.equal(broadcastMsg.id, 'foo');
t.equal(broadcastMsg.name, 'bar');
t.end();
});