From 26c928d10b9dfaf31a10a46a978b6d50824f74c0 Mon Sep 17 00:00:00 2001 From: Valerie R Young Date: Wed, 31 Oct 2018 17:37:51 -0400 Subject: [PATCH 1/4] Handle unknown opcode in input --- src/serialization/sb2.js | 44 ++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/serialization/sb2.js b/src/serialization/sb2.js index 5021c14df..b62b41a8e 100644 --- a/src/serialization/sb2.js +++ b/src/serialization/sb2.js @@ -843,6 +843,7 @@ const parseBlock = function (sb2block, addBroadcastMsg, getVariableId, extension for (let i = 0; i < blockMetadata.argMap.length; i++) { const expectedArg = blockMetadata.argMap[i]; const providedArg = sb2block[i + 1]; // (i = 0 is opcode) + // Whether the input is obscuring a shadow. let shadowObscured = false; // Positional argument is an input. @@ -866,32 +867,35 @@ const parseBlock = function (sb2block, addBroadcastMsg, getVariableId, extension // Single block occupies the input. const parsedBlockDesc = parseBlock(providedArg, addBroadcastMsg, getVariableId, extensions, parseState, comments, commentIndex); - innerBlocks = [parsedBlockDesc[0]]; + innerBlocks = parsedBlockDesc[0] ? [parsedBlockDesc[0]] : []; // Update commentIndex commentIndex = parsedBlockDesc[1]; } parseState.expectedArg = parentExpectedArg; - // Check if innerBlocks is an empty list. - // This indicates that all the inner blocks from the sb2 have - // unknown opcodes and have been skipped. - if (innerBlocks.length === 0) continue; - let previousBlock = null; - for (let j = 0; j < innerBlocks.length; j++) { - if (j === 0) { - innerBlocks[j].parent = activeBlock.id; - } else { - innerBlocks[j].parent = previousBlock; - } - previousBlock = innerBlocks[j].id; - } + // Obscures any shadow. shadowObscured = true; - activeBlock.inputs[expectedArg.inputName].block = ( - innerBlocks[0].id - ); - activeBlock.children = ( - activeBlock.children.concat(innerBlocks) - ); + + // Check if innerBlocks is not an empty list. + // An empty list indicates that all the inner blocks from the sb2 have + // unknown opcodes and have been skipped. + if (innerBlocks.length > 0) { + let previousBlock = null; + for (let j = 0; j < innerBlocks.length; j++) { + if (j === 0) { + innerBlocks[j].parent = activeBlock.id; + } else { + innerBlocks[j].parent = previousBlock; + } + previousBlock = innerBlocks[j].id; + } + activeBlock.inputs[expectedArg.inputName].block = ( + innerBlocks[0].id + ); + activeBlock.children = ( + activeBlock.children.concat(innerBlocks) + ); + } } // Generate a shadow block to occupy the input. if (!expectedArg.inputOp) { From 2c76d3bf71563a1b361f7e4e5ff222ddf14425c5 Mon Sep 17 00:00:00 2001 From: Valerie R Young Date: Mon, 5 Nov 2018 13:23:31 -0500 Subject: [PATCH 2/4] Add unit test for unknown opcode inputs --- .../unknown-opcode-as-reporter-block.sb2 | Bin 0 -> 4368 bytes .../unknown-opcode-as-reporter-block.js | 54 ++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 test/fixtures/unknown-opcode-as-reporter-block.sb2 create mode 100644 test/integration/unknown-opcode-as-reporter-block.js diff --git a/test/fixtures/unknown-opcode-as-reporter-block.sb2 b/test/fixtures/unknown-opcode-as-reporter-block.sb2 new file mode 100644 index 0000000000000000000000000000000000000000..1999dcb9a2e22cb5b0ebb5ef115186cb41c73c6d GIT binary patch literal 4368 zcmWIWW@h1HU|`^2V4INY>&mFB)XL1j5XsKKzylO5D9X=DO)k;PD$dXA4b9EJZNc+z z&Oa{a0}a*-K4-sCx%-eWw@8|8%kHGR-u#7zC(LB6r>Z(nx}4+u|F`F-XrY|Lit;*> z9vyC9a-zn5w!*ZW`wzJ;w6?xexyN7??ltk#rfE)^*I!32F`4Z7VAlDn-g#UL@+}x@ zeLt|-N_zS}M9={_CP)fa!R zsM{TMYMaE0Q%<$Xau1H?*qvUMDfHCQsGG@tW?Celr`>F}i)ZQ%?UrK-H*H+XH0ji3 z{^x6FC9h1bocFqYty=n?L%;Z(yz0zMg4LF+I?Z^|?{ctj!LJ#GVb!r)Sh#l_i*J;^ zbg%PMTI!ASO|C*s{eLqBo(Wb=_|@%d5M6Qd3jdzWlgLtAy_1v|-&px?vv-hqMEpkQ!%H+gm+g4*N-9hB z>`bAOrMo*{{7#$Xw&>YXnX1f9uB>9-hi2upE^Rw!D0m_6nDvQ&_q@Ndh3Xy?^9wlK z>8D>-vgd|o!_8!X`2Cjl$NM zZn>$4jC9|unqrpH>y#^c=Q?9Z@TD6!yBz@t_Id2oTq0>=YxrxyvOOV+nOyq%{!dm5S5_*m|0TQlo_sQk!CvX)c{zelD>Ik& z1bL)t$H{h|PA)7};0x?Hv@21@r@{W~R{IOh8*R&7CAhBg-@7n-pATo^%g3?2nY&#A z7bbprwk0m)TcOn4g;S@szwrxCasR-w_HBdR*CT7izes!)<1XCr{fg&u(Ot?(NoSZZ z2_D|>c3c13cZSpt?s0e1+dY|;FI*J6HZM(j#m%QVt3R19?*3EoP`Bp%ci+(43;(vu z^@b`p#OEFGQP`Du-^;1sP0P0Izh&<$*ROd!$*eltzJH&~<#4h4u`Z2o|K;s%{1WIp z{e9J|{)1oFTvu(M^ETOi_U(*En*Uj1wnX#2T^6`IB+zez2A|IL_wUvour9yqZ)`i; zX1?uz_5f&hWdLW_4HtzTzh_}!0AW^Ob~Vr|$V=}G@N?(ok^*IFUQZ8~AO;4;2SA*` z!3GrRH`h>LU|^~Bba4!+xb^m`AulkaAKoDQw7*iTGtR8V<|HFS@kF4Q1PB=zoprP)o!L?SfSwfTbY_gGxk0VoSt2Scz!K2y6@;F=+do zKl3B%c~h0!bgild`14qDE5H9gp_VLbN*AMwn!a!DvC+giCOiC-KYv_d;^6iY zm?U_U&zw_|sq**SZ_~cq{d)bU{Qo|d=^Wx*T^yk-iT?t;8JV~ka1Rs!lMfO=9yUPe z#NKB?Xj=~)cmVfc(6yjf>If|dIiOWMx)$_AkI-@j*yAzK17?8$Z&px`h=BzNF9T_H IP#$0a0FgMr&Hw-a literal 0 HcmV?d00001 diff --git a/test/integration/unknown-opcode-as-reporter-block.js b/test/integration/unknown-opcode-as-reporter-block.js new file mode 100644 index 000000000..c9dc4a19d --- /dev/null +++ b/test/integration/unknown-opcode-as-reporter-block.js @@ -0,0 +1,54 @@ +const path = require('path'); +const test = require('tap').test; +const makeTestStorage = require('../fixtures/make-test-storage'); +const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; +const VirtualMachine = require('../../src/index'); + +const uri = path.resolve(__dirname, '../fixtures/unknown-opcode-as-reporter-block.sb2'); +const project = readFileToBuffer(uri); + +test('unknown opcode', t => { + const vm = new VirtualMachine(); + vm.attachStorage(makeTestStorage()); + + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + vm.loadProject(project).then(() => { + vm.greenFlag(); + + // The project has 4 blocks in a single stack: + // when green flag + // if "unknown block" + // set volume to "unknown block" + // play sound "unknown block" + // the "unknown block" has unknown opcode and was created by + // dragging a discontinued extension. + // It should be parsed in without error and a shadow block + // should be created where appropriate. + const blocks = vm.runtime.targets[0].blocks; + const topBlockId = blocks.getScripts()[0]; + const secondBlockId = blocks.getNextBlock(topBlockId); + const thirdBlockId = blocks.getNextBlock(secondBlockId); + const fourthBlockId = blocks.getNextBlock(thirdBlockId); + + t.equal(blocks.getBlock(topBlockId).opcode, 'event_whenflagclicked'); + t.equal(blocks.getBlock(secondBlockId).opcode, 'control_wait_until'); + t.equal(blocks.getBlock(thirdBlockId).opcode, 'sound_setvolumeto'); + t.equal(blocks.getBlock(fourthBlockId).opcode, 'sound_play'); + + const secondBlockInputId = blocks.getBlock(secondBlockId).inputs.CONDITION.block; + const thirdBlockInputId = blocks.getBlock(thirdBlockId).inputs.VOLUME.block; + const fourthBlockInputId = blocks.getBlock(fourthBlockId).inputs.SOUND_MENU.block; + + t.equal(secondBlockInputId, null); + t.true(blocks.getBlock(thirdBlockInputId).shadow) + t.equal(blocks.getBlock(thirdBlockInputId).opcode, 'math_number'); + t.true(blocks.getBlock(fourthBlockInputId).shadow); + t.equal(blocks.getBlock(fourthBlockInputId).opcode, 'sound_sounds_menu'); + + t.end(); + process.nextTick(process.exit); + }); +}); From b64d18b6276a1052c32613392fd9a685b2821b1c Mon Sep 17 00:00:00 2001 From: Valerie R Young Date: Mon, 5 Nov 2018 15:16:57 -0500 Subject: [PATCH 3/4] Satisfy linter --- test/integration/unknown-opcode-as-reporter-block.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/unknown-opcode-as-reporter-block.js b/test/integration/unknown-opcode-as-reporter-block.js index c9dc4a19d..b07d3b5c5 100644 --- a/test/integration/unknown-opcode-as-reporter-block.js +++ b/test/integration/unknown-opcode-as-reporter-block.js @@ -39,11 +39,11 @@ test('unknown opcode', t => { t.equal(blocks.getBlock(fourthBlockId).opcode, 'sound_play'); const secondBlockInputId = blocks.getBlock(secondBlockId).inputs.CONDITION.block; - const thirdBlockInputId = blocks.getBlock(thirdBlockId).inputs.VOLUME.block; + const thirdBlockInputId = blocks.getBlock(thirdBlockId).inputs.VOLUME.block; const fourthBlockInputId = blocks.getBlock(fourthBlockId).inputs.SOUND_MENU.block; t.equal(secondBlockInputId, null); - t.true(blocks.getBlock(thirdBlockInputId).shadow) + t.true(blocks.getBlock(thirdBlockInputId).shadow); t.equal(blocks.getBlock(thirdBlockInputId).opcode, 'math_number'); t.true(blocks.getBlock(fourthBlockInputId).shadow); t.equal(blocks.getBlock(fourthBlockInputId).opcode, 'sound_sounds_menu'); From ebd3b46cc2360269a8af12c5d477705821e8520d Mon Sep 17 00:00:00 2001 From: Valerie R Young Date: Wed, 14 Nov 2018 14:24:09 -0500 Subject: [PATCH 4/4] Address feedback --- src/serialization/sb2.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/serialization/sb2.js b/src/serialization/sb2.js index b62b41a8e..9ee3b2f37 100644 --- a/src/serialization/sb2.js +++ b/src/serialization/sb2.js @@ -843,7 +843,6 @@ const parseBlock = function (sb2block, addBroadcastMsg, getVariableId, extension for (let i = 0; i < blockMetadata.argMap.length; i++) { const expectedArg = blockMetadata.argMap[i]; const providedArg = sb2block[i + 1]; // (i = 0 is opcode) - // Whether the input is obscuring a shadow. let shadowObscured = false; // Positional argument is an input. @@ -873,9 +872,6 @@ const parseBlock = function (sb2block, addBroadcastMsg, getVariableId, extension } parseState.expectedArg = parentExpectedArg; - // Obscures any shadow. - shadowObscured = true; - // Check if innerBlocks is not an empty list. // An empty list indicates that all the inner blocks from the sb2 have // unknown opcodes and have been skipped. @@ -896,6 +892,9 @@ const parseBlock = function (sb2block, addBroadcastMsg, getVariableId, extension activeBlock.children.concat(innerBlocks) ); } + + // Obscures any shadow. + shadowObscured = true; } // Generate a shadow block to occupy the input. if (!expectedArg.inputOp) {