Ignore video sensing monitor and import music tempo monitor unless it is hidden. Load extensions for visible monitors. Add tests for new functionality.

This commit is contained in:
Karishma Chadha 2018-11-09 00:09:54 -05:00
parent fe186913ac
commit cfa71723eb
8 changed files with 137 additions and 29 deletions

View file

@ -245,17 +245,42 @@ const globalBroadcastMsgStateGenerator = (function () {
* @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here.
*/
const parseMonitorObject = (object, runtime, targets, extensions) => {
let target = null;
// In scratch 2.0, there are two monitors that now correspond to extension
// blocks (tempo and video motion/direction). In the case of the
// video motion/direction block, this reporter is not monitorable in Scratch 3.0.
// In the case of the tempo block, we should import it and load the music extension
// only when the monitor is actually visible.
const opcode = specMap[object.cmd].opcode;
const extIndex = opcode.indexOf('_');
const extID = opcode.substring(0, extIndex);
// All non-core extensions should be added by blocks at this point
// We can assume this is an unintended monitor and skip parsing if it belongs to a non-core extension
if (CORE_EXTENSIONS.indexOf(extID) === -1) {
if (extID !== '') return;
if (extID === 'videoSensing') {
return;
} else if (CORE_EXTENSIONS.indexOf(extID) === -1 && extID !== '' &&
!extensions.extensionIDs.has(extID) && !object.visible) {
// Don't import this monitor if it refers to a non-core extension that
// doesn't exist anywhere else in the project and it isn't visible.
// This should only apply to the tempo block at this point since
// there are no other sb2 blocks that are now extension monitors.
return;
}
// if (!object.visible) {
// // If the monitor is invisible, check to see if it tries to load a new extension
// // (e.g. one that hasn't already been loaded by an actual block in the project).
// // If so, exit without importing the monitor.
//
//
// // All non-core extensions should be added by blocks at this point
// // We can assume this is an unintended monitor and skip parsing if it belongs to a non-core extension
// if () {
// if ( && !extensions.has(extID)) return;
// }
// }
let target = null;
// List blocks don't come in with their target name set.
// Find the target by searching for a target with matching variable name/type.
if (!object.hasOwnProperty('target')) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,107 @@
const path = require('path');
const test = require('tap').test;
const makeTestStorage = require('../fixtures/make-test-storage');
const {readFileToBuffer, extractProjectJson} = require('../fixtures/readProjectFile');
const VirtualMachine = require('../../src/index');
const sb2 = require('../../src/serialization/sb2');
const invisibleVideoMonitorProjectUri = path.resolve(__dirname, '../fixtures/invisible-video-monitor.sb2');
const invisibleVideoMonitorProject = readFileToBuffer(invisibleVideoMonitorProjectUri);
const visibleVideoMonitorProjectUri = path.resolve(
__dirname, '../fixtures/visible-video-monitor-no-other-video-blocks.sb2');
const visibleVideoMonitorProject = readFileToBuffer(visibleVideoMonitorProjectUri);
const visibleVideoMonitorAndBlocksProjectUri = path.resolve(
__dirname, '../fixtures/visible-video-monitor-and-video-blocks.sb2');
const visibleVideoMonitorAndBlocksProject = extractProjectJson(visibleVideoMonitorAndBlocksProjectUri);
const invisibleTempoMonitorProjectUri = path.resolve(
__dirname, '../fixtures/invisible-tempo-monitor-no-other-music-blocks.sb2');
const invisibleTempoMonitorProject = readFileToBuffer(invisibleTempoMonitorProjectUri);
const visibleTempoMonitorProjectUri = path.resolve(
__dirname, '../fixtures/visible-tempo-monitor-no-other-music-blocks.sb2');
const visibleTempoMonitorProject = readFileToBuffer(visibleTempoMonitorProjectUri);
test('loading sb2 project with invisible video monitor should not load monitor or extension', t => {
const vm = new VirtualMachine();
vm.attachStorage(makeTestStorage());
// Start VM, load project, and run
vm.start();
vm.clear();
vm.setCompatibilityMode(false);
vm.setTurboMode(false);
vm.loadProject(invisibleVideoMonitorProject).then(() => {
t.equal(vm.extensionManager.isExtensionLoaded('videoSensing'), false);
t.equal(vm.runtime._monitorState.size, 0);
t.end();
});
});
test('loading sb2 project with visible video monitor should not load extension', t => {
const vm = new VirtualMachine();
vm.attachStorage(makeTestStorage());
// Start VM, load project, and run
vm.start();
vm.clear();
vm.setCompatibilityMode(false);
vm.setTurboMode(false);
vm.loadProject(visibleVideoMonitorProject).then(() => {
t.equal(vm.extensionManager.isExtensionLoaded('videoSensing'), false);
t.equal(vm.runtime._monitorState.size, 0);
t.end();
});
});
// This test looks a little different than the rest because loading a project with
// the video sensing block requires a mock renderer and other setup, so instead
// we are just using deserialize to test what we need instead
test('sb2 project with video sensing blocks and monitor should load extension but not monitor', t => {
const vm = new VirtualMachine();
sb2.deserialize(visibleVideoMonitorAndBlocksProject, vm.runtime).then(project => {
// Extension loads but monitor does not
project.extensions.extensionIDs.has('videoSensing');
// Non-core extension monitors haven't been added to the runtime
t.equal(vm.runtime._monitorState.size, 0);
t.end();
});
});
test('sb2 project with invisible music monitor should not load monitor or extension', t => {
const vm = new VirtualMachine();
vm.attachStorage(makeTestStorage());
// Start VM, load project, and run
vm.start();
vm.clear();
vm.setCompatibilityMode(false);
vm.setTurboMode(false);
vm.loadProject(invisibleTempoMonitorProject).then(() => {
t.equal(vm.extensionManager.isExtensionLoaded('music'), false);
t.equal(vm.runtime._monitorState.size, 0);
t.end();
});
});
test('sb2 project with visible music monitor should load monitor and extension', t => {
const vm = new VirtualMachine();
vm.attachStorage(makeTestStorage());
// Start VM, load project, and run
vm.start();
vm.clear();
vm.setCompatibilityMode(false);
vm.setTurboMode(false);
vm.loadProject(visibleTempoMonitorProject).then(() => {
t.equal(vm.extensionManager.isExtensionLoaded('music'), true);
t.equal(vm.runtime._monitorState.size, 1);
t.equal(vm.runtime._monitorState.has('music_getTempo'), true);
t.equal(vm.runtime._monitorState.get('music_getTempo').visible, true);
t.end();
process.nextTick(process.exit); // This is needed because this is the end of the last test in this file!!
});
});

View file

@ -5,7 +5,6 @@ const extractProjectJson = require('../fixtures/readProjectFile').extractProject
const RenderedTarget = require('../../src/sprites/rendered-target');
const Runtime = require('../../src/engine/runtime');
const sb2 = require('../../src/serialization/sb2');
const specMap = require('../../src/serialization/sb2_specmap.js');
test('spec', t => {
t.type(sb2, 'object');
@ -103,26 +102,3 @@ test('Ordering', t => {
t.end();
});
});
test('Prevent monitors from adding non-core extensions', t => {
const rt = new Runtime();
// This test project's video motion reporter block was checked, saved, then unchecked and saved
const videoSensingMonitor = path.resolve(__dirname, '../fixtures/invisible-video-monitor.sb2');
const projectJSON = extractProjectJson(videoSensingMonitor);
sb2.deserialize(projectJSON, rt).then(project => {
for (const child of projectJSON.children) {
// Check that monitor's extension hasn't been added to the serialized project's extensions
if (child.cmd) {
const opcode = specMap[child.cmd].opcode;
const extIndex = opcode.indexOf('_');
const extID = opcode.substring(0, extIndex);
t.notOk(project.extensions.extensionIDs.has(extID));
}
}
// Non-core extension monitors haven't been added to the runtime
t.equal(rt._monitorState.size, 0);
t.end();
});
});