Merge pull request #768 from mzgoddard/broadcast-and-wait-chained

Broadcast and wait chained
This commit is contained in:
Ray Schamp 2017-11-16 11:48:23 -05:00 committed by GitHub
commit 29614044ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 104 additions and 4 deletions

View file

@ -804,6 +804,7 @@ class Runtime extends EventEmitter {
* This is used by `startHats` to and is necessary to ensure 2.0-like execution order.
* Test project: https://scratch.mit.edu/projects/130183108/
* @param {!Thread} thread Thread object to restart.
* @return {Thread} The restarted thread.
*/
_restartThread (thread) {
const newThread = new Thread(thread.topBlock);
@ -814,9 +815,10 @@ class Runtime extends EventEmitter {
const i = this.threads.indexOf(thread);
if (i > -1) {
this.threads[i] = newThread;
} else {
this.threads.push(thread);
return newThread;
}
this.threads.push(thread);
return thread;
}
/**
@ -825,7 +827,11 @@ class Runtime extends EventEmitter {
* @return {boolean} True if the thread is active/running.
*/
isActiveThread (thread) {
return this.threads.indexOf(thread) > -1;
return (
(
thread.stack.length > 0 &&
thread.status !== Thread.STATUS_DONE) &&
this.threads.indexOf(thread) > -1);
}
/**
@ -972,7 +978,7 @@ class Runtime extends EventEmitter {
if (instance.threads[i].topBlock === topBlockId &&
!instance.threads[i].stackClick && // stack click threads and hat threads can coexist
instance.threads[i].target === target) {
instance._restartThread(instance.threads[i]);
newThreads.push(instance._restartThread(instance.threads[i]));
return;
}
}

94
test/unit/blocks_event.js Normal file
View file

@ -0,0 +1,94 @@
const test = require('tap').test;
const Blocks = require('../../src/engine/blocks');
const BlockUtility = require('../../src/engine/block-utility');
const Event = require('../../src/blocks/scratch3_event');
const Runtime = require('../../src/engine/runtime');
const Target = require('../../src/engine/target');
const Thread = require('../../src/engine/thread');
test('#760 - broadcastAndWait', t => {
const broadcastAndWaitBlock = {
id: 'broadcastAndWaitBlock',
fields: {
BROADCAST_OPTION: {
id: 'BROADCAST_OPTION',
value: 'message'
}
},
inputs: Object,
block: 'fakeBlock',
opcode: 'event_broadcastandwait',
next: null,
parent: null,
shadow: false,
topLevel: true,
x: 0,
y: 0
};
const receiveMessageBlock = {
id: 'receiveMessageBlock',
fields: {
BROADCAST_OPTION: {
id: 'BROADCAST_OPTION',
value: 'message'
}
},
inputs: Object,
block: 'fakeBlock',
opcode: 'event_whenbroadcastreceived',
next: null,
parent: null,
shadow: false,
topLevel: true,
x: 0,
y: 0
};
const rt = new Runtime();
const e = new Event(rt);
const b = new Blocks();
b.createBlock(broadcastAndWaitBlock);
b.createBlock(receiveMessageBlock);
const tgt = new Target(rt, b);
rt.targets.push(tgt);
let th = rt._pushThread('broadcastAndWaitBlock', t);
const util = new BlockUtility();
util.sequencer = rt.sequencer;
util.thread = th;
// creates threads
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util);
t.strictEqual(rt.threads.length, 2);
t.strictEqual(rt.threads[1].topBlock, 'receiveMessageBlock');
// yields when some thread is active
t.strictEqual(th.status, Thread.STATUS_YIELD);
th.status = Thread.STATUS_RUNNING;
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util);
t.strictEqual(th.status, Thread.STATUS_YIELD);
// does not yield once all threads are done
th.status = Thread.STATUS_RUNNING;
rt.threads[1].status = Thread.STATUS_DONE;
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util);
t.strictEqual(th.status, Thread.STATUS_RUNNING);
// restarts done threads that are in runtime threads
th = rt._pushThread('broadcastAndWaitBlock', tgt);
util.thread = th;
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util);
t.strictEqual(rt.threads.length, 3);
t.strictEqual(rt.threads[1].status, Thread.STATUS_RUNNING);
t.strictEqual(th.status, Thread.STATUS_YIELD);
// yields when some restarted thread is active
th.status = Thread.STATUS_RUNNING;
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util);
t.strictEqual(th.status, Thread.STATUS_YIELD);
// does not yield once all threads are done
th.status = Thread.STATUS_RUNNING;
rt.threads[1].status = Thread.STATUS_DONE;
e.broadcastAndWait({BROADCAST_OPTION: 'message'}, util);
t.strictEqual(th.status, Thread.STATUS_RUNNING);
t.end();
});