forked from scratchfoundation/scratch-vm
-
-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a lot of event and predicate hat tests
- Loading branch information
1 parent
0ab2b54
commit 32c2e1b
Showing
2 changed files
with
192 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const {test} = require('tap'); | ||
const VM = require('../../src/virtual-machine'); | ||
const BlockType = require('../../src/extension-support/block-type'); | ||
const ArgumentType = require('../../src/extension-support/argument-type'); | ||
|
||
const compilerAndInterpreter = (name, callback) => { | ||
test(`${name} - interpreted`, t => { | ||
callback(t, { | ||
enabled: false | ||
}); | ||
}); | ||
test(`${name} - compiled`, t => { | ||
callback(t, { | ||
enabled: true | ||
}); | ||
}); | ||
}; | ||
|
||
const fixture = fs.readFileSync(path.join(__dirname, '..', 'fixtures', 'tw-hats-and-events.sb3')); | ||
|
||
compilerAndInterpreter('hats and events', (t, co) => { | ||
const vm = new VM(); | ||
vm.setCompilerOptions(co); | ||
|
||
let log = []; | ||
let hatReturns = false; | ||
class TestExtension { | ||
getInfo () { | ||
return { | ||
id: 'testpredicate', | ||
name: 'Test Predicate', | ||
blocks: [ | ||
{ | ||
opcode: 'event', | ||
blockType: BlockType.EVENT, | ||
text: 'event block', | ||
isEdgeActivated: false | ||
}, | ||
{ | ||
opcode: 'hat', | ||
blockType: BlockType.HAT, | ||
text: 'hat block', | ||
isEdgeActivated: false | ||
}, | ||
{ | ||
opcode: 'complexhat', | ||
blockType: BlockType.HAT, | ||
text: 'complex hat [MENU] if [INPUT]', | ||
isEdgeActivated: false, | ||
arguments: { | ||
MENU: { | ||
menu: 'test' | ||
}, | ||
INPUT: { | ||
type: ArgumentType.STRING, | ||
defaultValue: 'default' | ||
} | ||
} | ||
} | ||
], | ||
menus: { | ||
test: { | ||
acceptReporters: false, | ||
items: ['a', 'b', 'c'] | ||
} | ||
} | ||
}; | ||
} | ||
event () { | ||
log.push('this should never run'); | ||
} | ||
hat () { | ||
log.push(`hat ${hatReturns}`); | ||
return hatReturns; | ||
} | ||
complexhat ({INPUT}) { | ||
log.push(`complex hat ${INPUT}`); | ||
return !!INPUT; | ||
} | ||
} | ||
vm.extensionManager.addBuiltinExtension('testpredicate', TestExtension); | ||
|
||
vm.on('COMPILE_ERROR', () => { | ||
t.fail('Compile error'); | ||
}); | ||
|
||
vm.loadProject(fixture).then(async () => { | ||
log = vm.runtime.getTargetForStage().lookupVariableByNameAndType('log', 'list').value; | ||
t.same(log, [], 'sanity check - log starts empty'); | ||
|
||
// Let it run for a bit. Nothing should happen on its own. | ||
for (let i = 0; i < 5; i++) { | ||
vm.runtime._step(); | ||
} | ||
t.same(log, [], 'nothing happens initially'); | ||
|
||
// See if events work | ||
vm.runtime.startHats('testpredicate_event'); | ||
t.same(log, [], 'event function does not get called, even if it exists'); | ||
vm.runtime._step(); | ||
t.same(log, ['event'], 'ran event script'); | ||
|
||
log.length = 0; | ||
|
||
// Test hat that returns false | ||
hatReturns = false; | ||
vm.runtime.startHats('testpredicate_hat'); | ||
t.same(log, ['hat false'], 'ran hat function'); | ||
vm.runtime._step(); | ||
t.same(log, ['hat false'], 'did not run hat script'); | ||
|
||
// Test hat that returns true | ||
hatReturns = true; | ||
vm.runtime.startHats('testpredicate_hat'); | ||
t.same(log, [ | ||
'hat false', | ||
'hat true' | ||
], 'ran hat function'); | ||
vm.runtime._step(); | ||
t.same(log, [ | ||
'hat false', | ||
'hat true', | ||
'hat' | ||
], 'ran hat script'); | ||
|
||
log.length = 0; | ||
|
||
// Test hat that returns false in a Promise | ||
hatReturns = Promise.resolve(false); | ||
vm.runtime.startHats('testpredicate_hat'); | ||
t.same(log, ['hat [object Promise]'], 'ran hat function'); | ||
vm.runtime._step(); | ||
t.same(log, ['hat [object Promise]'], 'hat script does not run before promise finishes'); | ||
await Promise.resolve(); // Allow promise to be processed | ||
vm.runtime._step(); | ||
t.same(log, ['hat [object Promise]'], 'hat script still does not run'); | ||
|
||
log.length = 0; | ||
|
||
// Test hat that returns true in a Promise | ||
hatReturns = Promise.resolve(true); | ||
vm.runtime.startHats('testpredicate_hat'); | ||
t.same(log, ['hat [object Promise]'], 'ran hat function'); | ||
vm.runtime._step(); | ||
t.same(log, ['hat [object Promise]'], 'hat script does not run before promise finishes'); | ||
await Promise.resolve(); | ||
vm.runtime._step(); | ||
t.same(log, ['hat [object Promise]', 'hat'], 'hat script runs after promise finishes'); | ||
|
||
log.length = 0; | ||
|
||
// Test complex hat | ||
vm.runtime.startHats('testpredicate_complexhat', { | ||
MENU: 'a' | ||
}); | ||
t.same(log, [ | ||
'complex hat ', | ||
'complex hat 1' | ||
], 'ran complex hat functions'); | ||
vm.runtime._step(); | ||
t.same(log, [ | ||
'complex hat ', | ||
'complex hat 1', | ||
'complex hat a 2' | ||
], 'ran complex hat script'); | ||
|
||
log.length = 0; | ||
|
||
// Test complex hat with a complex input | ||
vm.runtime.startHats('testpredicate_complexhat', { | ||
MENU: 'b' | ||
}); | ||
t.same(log, [], 'control flow in complex inputs is not run immediately'); | ||
vm.runtime._step(); | ||
t.same(log, [ | ||
'evaluated block ', | ||
'evaluated block 1' | ||
], 'evaluated complex inputs but not hat function'); | ||
vm.runtime._step(); | ||
t.same(log, [ | ||
'evaluated block ', | ||
'evaluated block 1', | ||
'complex hat ', | ||
'complex hat 1', | ||
'complex hat b 2' | ||
], 'evaluated complex hat functions and scripts'); | ||
|
||
t.end(); | ||
}); | ||
}); |