From 70a78cf7db250b7bdce8b30f0fab2a5808f01ac6 Mon Sep 17 00:00:00 2001 From: Karishma Chadha <kchadha@scratch.mit.edu> Date: Fri, 13 May 2022 18:34:34 -0400 Subject: [PATCH] Add tests for load costume error handling. Fix issue where asset data was not getting saved out properly. --- package.json | 1 + src/import/load-costume.js | 12 ++- src/virtual-machine.js | 11 +-- test/fixtures/corrupt_svg.sb3 | Bin 0 -> 4856 bytes test/fixtures/corrupt_svg.sprite3 | Bin 0 -> 2713 bytes test/fixtures/default.sb3 | Bin 0 -> 41932 bytes test/fixtures/fake-renderer.js | 13 +++ test/fixtures/make-test-storage.js | 4 +- test/fixtures/missing_svg.sb3 | Bin 0 -> 3446 bytes test/fixtures/missing_svg.sprite3 | Bin 0 -> 1949 bytes test/fixtures/readProjectFile.js | 5 + test/integration/sb3_corrupted_svg.js | 107 ++++++++++++++++++++++ test/integration/sb3_missing_svg.js | 87 ++++++++++++++++++ test/integration/sprite3_corrupted_svg.js | 106 +++++++++++++++++++++ test/integration/sprite3_missing_svg.js | 85 +++++++++++++++++ 15 files changed, 418 insertions(+), 13 deletions(-) create mode 100644 test/fixtures/corrupt_svg.sb3 create mode 100644 test/fixtures/corrupt_svg.sprite3 create mode 100644 test/fixtures/default.sb3 create mode 100644 test/fixtures/missing_svg.sb3 create mode 100644 test/fixtures/missing_svg.sprite3 create mode 100644 test/integration/sb3_corrupted_svg.js create mode 100644 test/integration/sb3_missing_svg.js create mode 100644 test/integration/sprite3_corrupted_svg.js create mode 100644 test/integration/sprite3_missing_svg.js diff --git a/package.json b/package.json index 136318cec..68d1ba16d 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "gh-pages": "1.2.0", "in-publish": "2.0.1", "jsdoc": "3.6.6", + "js-md5": "0.7.3", "json": "^9.0.4", "lodash.defaultsdeep": "4.6.1", "pngjs": "3.3.3", diff --git a/src/import/load-costume.js b/src/import/load-costume.js index b3b73c591..58f3cacf9 100644 --- a/src/import/load-costume.js +++ b/src/import/load-costume.js @@ -250,9 +250,9 @@ const loadBitmap_ = function (costume, runtime, _rotationCenter) { // Handle all manner of costume errors with a Gray Question Mark (default costume) // and preserve as much of the original costume data as possible // Returns a promise of a costume -const handleCostumeLoadError = function (costume, runtime) { - // Keep track of the old assetId until we're done loading the default costume - // const oldAsset = costume.asset; // could be null +const handleCostumeLoadError = function (costume, runtime) { + // Keep track of the old asset information until we're done loading the default costume + const oldAsset = costume.asset; // could be null const oldAssetId = costume.assetId; const oldRotationX = costume.rotationCenterX; const oldRotationY = costume.rotationCenterY; @@ -270,8 +270,10 @@ const handleCostumeLoadError = function (costume, runtime) { loadedCostume.broken = {}; loadedCostume.broken.assetId = oldAssetId; loadedCostume.broken.md5 = `${oldAssetId}.${costume.dataFormat}`; + // Should be null if we got here because the costume was missing - loadedCostume.broken.asset = runtime.storage.get(oldAssetId); + loadedCostume.broken.asset = oldAsset; + loadedCostume.broken.rotationCenterX = oldRotationX; loadedCostume.broken.rotationCenterY = oldRotationY; return loadedCostume; @@ -310,7 +312,7 @@ const loadCostumeFromAsset = function (costume, runtime, optVersion) { if (costume.asset.assetType.runtimeFormat === AssetType.ImageVector.runtimeFormat) { return loadVector_(costume, runtime, rotationCenter, optVersion) .catch(error => { - log.warn(`Error loading vector image: ${error.name}: ${error.message}`); + log.warn(`Error loading vector image: ${error}`); return handleCostumeLoadError(costume, runtime); }); diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 9abbf6791..3e67ec91e 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -427,11 +427,9 @@ class VirtualMachine extends EventEmitter { * specified by optZipType or blob by default. */ exportSprite (targetId, optZipType) { - const sb3 = require('./serialization/sb3'); - const soundDescs = serializeSounds(this.runtime, targetId); const costumeDescs = serializeCostumes(this.runtime, targetId); - const spriteJson = StringUtil.stringify(sb3.serialize(this.runtime, targetId)); + const spriteJson = this.toJSON(targetId); const zip = new JSZip(); zip.file('sprite.json', spriteJson); @@ -448,12 +446,13 @@ class VirtualMachine extends EventEmitter { } /** - * Export project as a Scratch 3.0 JSON representation. + * Export project or sprite as a Scratch 3.0 JSON representation. + * @param {string=} optTargetId - Optional id of a sprite to serialize * @return {string} Serialized state of the runtime. */ - toJSON () { + toJSON (optTargetId) { const sb3 = require('./serialization/sb3'); - return StringUtil.stringify(sb3.serialize(this.runtime)); + return StringUtil.stringify(sb3.serialize(this.runtime, optTargetId)); } // TODO do we still need this function? Keeping it here so as not to introduce diff --git a/test/fixtures/corrupt_svg.sb3 b/test/fixtures/corrupt_svg.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..52fb93096f082385fc0aec5c32df6fff96e588b7 GIT binary patch literal 4856 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/corrupt_svg.sprite3 b/test/fixtures/corrupt_svg.sprite3 new file mode 100644 index 0000000000000000000000000000000000000000..1d9dd0b3dd08da0ca2ebdfd1c435b295e44d179e GIT binary patch literal 2713 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 G_vzmY6F1xd literal 0 HcmV?d00001 diff --git a/test/fixtures/default.sb3 b/test/fixtures/default.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..61b71838914e562a69f235781217de928d921b00 GIT binary patch literal 41932 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/fake-renderer.js b/test/fixtures/fake-renderer.js index dd0868767..f8343692e 100644 --- a/test/fixtures/fake-renderer.js +++ b/test/fixtures/fake-renderer.js @@ -4,6 +4,19 @@ const FakeRenderer = function () { this.y = 0; this.order = 0; this.spriteCount = 5; + this._nextSkinId = -1; +}; + +FakeRenderer.prototype.createSVGSkin = function () { + return this._nextSkinId++; +}; + +FakeRenderer.prototype.getSkinSize = function (d) { // eslint-disable-line no-unused-vars + return [0, 0]; +}; + +FakeRenderer.prototype.getSkinRotationCenter = function (d) { // eslint-disable-line no-unused-vars + return [0, 0]; }; FakeRenderer.prototype.createDrawable = function () { diff --git a/test/fixtures/make-test-storage.js b/test/fixtures/make-test-storage.js index 0179ca34a..1401a2c1e 100644 --- a/test/fixtures/make-test-storage.js +++ b/test/fixtures/make-test-storage.js @@ -39,8 +39,8 @@ const getAssetUrl = function (asset) { const makeTestStorage = function () { const storage = new ScratchStorage(); const AssetType = storage.AssetType; - storage.addWebSource([AssetType.Project], getProjectUrl); - storage.addWebSource([AssetType.ImageVector, AssetType.ImageBitmap, AssetType.Sound], getAssetUrl); + storage.addWebStore([AssetType.Project], getProjectUrl); + storage.addWebStore([AssetType.ImageVector, AssetType.ImageBitmap, AssetType.Sound], getAssetUrl); return storage; }; diff --git a/test/fixtures/missing_svg.sb3 b/test/fixtures/missing_svg.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..e0956c36f06c05e56a9de97f38882654b9158ee7 GIT binary patch literal 3446 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/missing_svg.sprite3 b/test/fixtures/missing_svg.sprite3 new file mode 100644 index 0000000000000000000000000000000000000000..5cc0986898c684baa0d736794cc4f0606e887c51 GIT binary patch literal 1949 zcmWIWW@Zs#0D<j!Eg@hAl#palU~tMQO;rdkEKMv*Rd6q@)bPzLF3!wL*VGRU;bmZ7 zW#FB(0f<3#X$3a}Bg<Dt1_rQk0bpY}7&uUjy#q8_8E9;Lysx9Pe{h7pUOX-vP%PMr zX+d&=XmWZ&Qo;vcpRf=7VI2VtOcNxS)di#(KWZtkeSB{qz$)YH)U?27LZ7C?o5p1= zf{N$n&zZk^dPKm4$*ZQ%o-v16Bqi}jNY&2Qp-bvdsl|8mt`qB=bL3_>A47mQJI9r@ zu;dt^b3sl<c*e315k}2S3=Asx!l<~QD6=G0FRM5|5A2(N>E1~jfj-g4^i6NjX}`k; z0)M7voe!K6{#eCbt8vFAZjQo;<9;a*j~wj35cKu_#@kaC#XZ<|e&)@M{0e8TC7oaR zGC)f1U`Mn613#;Mx9Tje)O>yLP2gZpl)}_I4#gI33auNxJ+?Ysdt^F&Rc-vEFkWVP z{khjN-)`<Ty2d(7g=bEZ{f8<BleXLL&wd(edxl?}RS>s5wlyNWvTeqNMQ<a{YW~rP zWeAF2c!<x!ws7&1%}%`+mI(6XoGt$*KVjp{YW_nP9__uv+%~t^Q@fin|MAx1zdXKk zkGO_DNvXYE-MH+`qpu%znHJwUk#~Mo(Hc+Jh>Mptoz~R++#}XgI;U*O3GX7??4ZkQ zXZX*lUAcRSqePT_v`FToxh57qlk#oWzF+1!@9(a^`u8jn*spHhuJ>WSKzd?JePPC$ zvVYlc7MwiI@$Ev&)aAnQ(=F9Z^3S(jSG;=Tdqq@?-PNN@*4}N`S};ZX%0UH-I%ZI8 z7BjP@!~oMKD9*6QrU6jK7GG>y7$;hqTbQSqBqy1r87G;W85<>;q@<*!CZ(C17@L{v zl_!?LqZt&%SfZKHfa(0-AWt_p4WMn|j$y88xg`n$z!b&^go4@(3`$`P3``6H3@M2v zi7Y@hR~eX@_p%r9z84LawNaj}@<?H|STS4Z$M{<bM|wABuAH>u=|=aXjt@UGy;ZyD z?v+@ZuUx>Dc+TaOtk!4#lUd9EPE_rEH^Xx4i@T3_=32QV6qIePT$FLcHC^26NzT@) zN%tDF+Y0CRolyMq$e=d%e&v&T^TL(B+hkTg_utVojkz;(qW`+DH)D7hYy#rn=Zj~C z`EjWfeu_MrzIfZ@ikUw)W!zfK*=Lp=u9>zdevjK%`4gX*Pkmi`Zjt<Iqaz<*9S~V< zsS)@w%*4}Ao0&!D_P$+jR`9L7xTojt9yS}j25*r_^`KbGHNrBl3XiT`tGRsFX6XwX zzAcrjvOf`cDlpr=R{r_V%hwwB$!`nYx8~}euUZmK#$O#<9CY+~gu_40zq<MG*Zn1@ z=RB@rs#54QYqP&(VWo1IZPIh;b8Y)M4v3x)e3{Krr>bDZ;keaensP9k{)@2lT8Ca8 zin_@9%9DMH(sk1dHg8P5l%qJ^-$~ynKh1kO?OOh;jZBjyjkPKaR%zSFe&I;@y#L{j z>))=exi9ekETg7yjQk2^5Bb%?>zRW-7d+c_|MmmpmuJ4Iu-z8^B;zIDB6X6#hVjWK z)91Vo+a6ZENdK~sNk<@FN<h9xHcrfzyX4>VPp4i@d*1T$!TX;-t}t<MdkIVuyvb+I zDalm%d+xVsU+#Xr{!{*cAIo$Oajq_oP?p4hp!7TcW9vFoV0r+h(g1HpCJ|=bWi~K5 zfx!Vs5QVFJC87j}SOY7=kqbmn84d#n8pDB1DwOCje}OCnm9xls7F5o{z?Mc8Mm+u^ rq0~jU5jm7WWdRIqY5W8Xcbp+fjgle2o0Sb@9Saa%1$u82D~JaGl?}7g literal 0 HcmV?d00001 diff --git a/test/fixtures/readProjectFile.js b/test/fixtures/readProjectFile.js index 8340ba228..254862cea 100644 --- a/test/fixtures/readProjectFile.js +++ b/test/fixtures/readProjectFile.js @@ -12,5 +12,10 @@ module.exports = { return JSON.parse(zip.readAsText(projectEntry.entryName, 'utf8')); } return null; + }, + extractAsset: function (path, assetFileName) { + const zip = new AdmZip(path); + const assetEntry = zip.getEntries().filter(item => item.entryName.match(assetFileName))[0]; + return assetEntry.getData(); } }; diff --git a/test/integration/sb3_corrupted_svg.js b/test/integration/sb3_corrupted_svg.js new file mode 100644 index 000000000..281c1c604 --- /dev/null +++ b/test/integration/sb3_corrupted_svg.js @@ -0,0 +1,107 @@ +/** + * This test mocks render breaking on loading a corrupted vector costume. + * The VM should handle this safely by displaying a Gray Question Mark, + * but keeping track of the original costume data and serializing the + * original costume data back out. The saved project.json should not + * reflect that the costume is broken and should therefore re-attempt + * to load the costume if the saved project is re-loaded. + */ +const path = require('path'); +const tap = require('tap'); +const md5 = require('js-md5'); +const makeTestStorage = require('../fixtures/make-test-storage'); +const FakeRenderer = require('../fixtures/fake-renderer'); +const {extractAsset, readFileToBuffer} = require('../fixtures/readProjectFile'); +const VirtualMachine = require('../../src/index'); +const {serializeCostumes} = require('../../src/serialization/serialize-assets'); + +const projectUri = path.resolve(__dirname, '../fixtures/corrupt_svg.sb3'); +const project = readFileToBuffer(projectUri); +const costumeFileName = 'a267f8b97ee9cf8aa9832aa0b4cfd9eb.svg'; +const originalCostume = extractAsset(projectUri, costumeFileName); +// We need to get the actual md5 because we hand modified the svg to corrupt it +// after we downloaded the project from Scratch +// Loading the project back into the VM will correct the assetId and md5 +const brokenCostumeMd5 = md5(originalCostume); + +let vm; +let defaultVectorAssetId; + +tap.beforeEach(() => { + const storage = makeTestStorage(); + + vm = new VirtualMachine(); + vm.attachStorage(storage); + defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageVector; + + // Mock renderer breaking on loading a corrupt costume + FakeRenderer.prototype.createSVGSkin = function (svgString) { + // Look for text added to costume to make it a corrupt svg + if (svgString.includes('<here is some')) { + throw new Error('mock createSVGSkin broke'); + } + return FakeRenderer._nextSkinId++; + }; + + vm.attachRenderer(new FakeRenderer()); + + return vm.loadProject(project); +}); + +const test = tap.test; + +test('load sb3 project with corrupted vector costume file', t => { + t.equal(vm.runtime.targets.length, 2); + + const stage = vm.runtime.targets[0]; + t.ok(stage.isStage); + + const blueGuySprite = vm.runtime.targets[1]; + t.equal(blueGuySprite.getName(), 'Blue Square Guy'); + t.equal(blueGuySprite.getCostumes().length, 1); + + const corruptedCostume = blueGuySprite.getCostumes()[0]; + t.equal(corruptedCostume.name, 'costume1'); + t.equal(corruptedCostume.assetId, defaultVectorAssetId); + t.equal(corruptedCostume.dataFormat, 'svg'); + // Runtime should have info about broken asset + t.ok(corruptedCostume.broken); + t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + // Verify that we saved the original asset data + t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); + + t.end(); +}); + +test('load and then save project with corrupted vector costume file', t => { + const resavedProject = JSON.parse(vm.toJSON()); + + t.equal(resavedProject.targets.length, 2); + + const stage = resavedProject.targets[0]; + t.ok(stage.isStage); + + const blueGuySprite = resavedProject.targets[1]; + t.equal(blueGuySprite.name, 'Blue Square Guy'); + t.equal(blueGuySprite.costumes.length, 1); + + const corruptedCostume = blueGuySprite.costumes[0]; + t.equal(corruptedCostume.name, 'costume1'); + // Resaved project costume should have the metadata that corresponds to the original broken costume + t.equal(corruptedCostume.assetId, brokenCostumeMd5); + t.equal(corruptedCostume.dataFormat, 'svg'); + // Test that we didn't save any data about the costume being broken + t.notOk(corruptedCostume.broken); + + t.end(); +}); + +test('serializeCostume saves orignal broken costume', t => { + const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[1].id); + t.equal(costumeDescs.length, 1); + const costume = costumeDescs[0]; + t.equal(costume.fileName, `${brokenCostumeMd5}.svg`); + t.equal(md5(costume.fileContent), brokenCostumeMd5); + t.end(); + process.nextTick(process.exit); +}); diff --git a/test/integration/sb3_missing_svg.js b/test/integration/sb3_missing_svg.js new file mode 100644 index 000000000..9e1445f5a --- /dev/null +++ b/test/integration/sb3_missing_svg.js @@ -0,0 +1,87 @@ +/** + * This test ensures that the VM gracefully handles an sb3 project with + * a missing vector costume. The VM should handle this safely by displaying + * a Gray Question Mark, but keeping track of the original costume data + * and serializing the original costume data back out. The saved project.json + * should not reflect that the costume is broken and should therefore re-attempt + * to load the costume if the saved project is re-loaded. + */ +const path = require('path'); +const tap = require('tap'); +const makeTestStorage = require('../fixtures/make-test-storage'); +const FakeRenderer = require('../fixtures/fake-renderer'); +const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; +const VirtualMachine = require('../../src/index'); + +const projectUri = path.resolve(__dirname, '../fixtures/missing_svg.sb3'); +const project = readFileToBuffer(projectUri); + +const missingCostumeAssetId = 'a267f8b97ee9cf8aa9832aa0b4cfd9eb'; + +let vm; + +tap.beforeEach(() => { + const storage = makeTestStorage(); + + // This line removes the webhelper from the list of available helpers. + // W/o the following line, this fails because storage doesn't handle the case + // where none of the tools have isGetSupported: true + // TODO: Remove this line when the related storage bug is resolved so that + // storage gracefully handles non-browser situations where assets are missing. + storage._helpers = [storage._helpers[0]]; + + vm = new VirtualMachine(); + vm.attachStorage(storage); + vm.attachRenderer(new FakeRenderer()); + + return vm.loadProject(project); +}); + +const test = tap.test; + +test('loading sb3 project with missing vector costume file', t => { + t.equal(vm.runtime.targets.length, 2); + + const stage = vm.runtime.targets[0]; + t.ok(stage.isStage); + + const blueGuySprite = vm.runtime.targets[1]; + t.equal(blueGuySprite.getName(), 'Blue Square Guy'); + t.equal(blueGuySprite.getCostumes().length, 1); + + const missingCostume = blueGuySprite.getCostumes()[0]; + t.equal(missingCostume.name, 'costume1'); + // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data + const defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageVector; + t.equal(missingCostume.assetId, defaultVectorAssetId); + t.equal(missingCostume.dataFormat, 'svg'); + // Runtime should have info about broken asset + t.ok(missingCostume.broken); + t.equal(missingCostume.broken.assetId, missingCostumeAssetId); + + t.end(); +}); + +test('load and then save sb3 project with missing costume file', t => { + const resavedProject = JSON.parse(vm.toJSON()); + + t.equal(resavedProject.targets.length, 2); + + const stage = resavedProject.targets[0]; + t.ok(stage.isStage); + + const blueGuySprite = resavedProject.targets[1]; + t.equal(blueGuySprite.name, 'Blue Square Guy'); + t.equal(blueGuySprite.costumes.length, 1); + + const missingCostume = blueGuySprite.costumes[0]; + t.equal(missingCostume.name, 'costume1'); + // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data + t.equal(missingCostume.assetId, missingCostumeAssetId); + t.equal(missingCostume.dataFormat, 'svg'); + // Test that we didn't save any data about the costume being broken + t.notOk(missingCostume.broken); + + t.end(); + process.nextTick(process.exit); +}); diff --git a/test/integration/sprite3_corrupted_svg.js b/test/integration/sprite3_corrupted_svg.js new file mode 100644 index 000000000..9bbe96bc9 --- /dev/null +++ b/test/integration/sprite3_corrupted_svg.js @@ -0,0 +1,106 @@ +/** + * This test mocks render breaking on loading a sprite with a + * corrupted vector costume. + * The VM should handle this safely by displaying a Gray Question Mark, + * but keeping track of the original costume data and serializing the + * original costume data back out. The saved project.json should not + * reflect that the costume is broken and should therefore re-attempt + * to load the costume if the saved project is re-loaded. + */ +const path = require('path'); +const tap = require('tap'); +const md5 = require('js-md5'); +const makeTestStorage = require('../fixtures/make-test-storage'); +const FakeRenderer = require('../fixtures/fake-renderer'); +const {extractAsset, readFileToBuffer} = require('../fixtures/readProjectFile'); +const VirtualMachine = require('../../src/index'); +const {serializeCostumes} = require('../../src/serialization/serialize-assets'); + +const projectUri = path.resolve(__dirname, '../fixtures/default.sb3'); +const project = readFileToBuffer(projectUri); + +const spriteUri = path.resolve(__dirname, '../fixtures/corrupt_svg.sprite3'); +const sprite = readFileToBuffer(spriteUri); + +const costumeFileName = 'a267f8b97ee9cf8aa9832aa0b4cfd9eb.svg'; +const originalCostume = extractAsset(spriteUri, costumeFileName); +// We need to get the actual md5 because we hand modified the svg to corrupt it +// after we downloaded the project from Scratch +// Loading the project back into the VM will correct the assetId and md5 +const brokenCostumeMd5 = md5(originalCostume); + +let vm; +let defaultVectorAssetId; + +tap.beforeEach(() => { + const storage = makeTestStorage(); + + vm = new VirtualMachine(); + vm.attachStorage(storage); + defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageVector; + + // Mock renderer breaking on loading a corrupt costume + FakeRenderer.prototype.createSVGSkin = function (svgString) { + // Look for text added to costume to make it a corrupt svg + if (svgString.includes('<here is some')) { + throw new Error('mock createSVGSkin broke'); + } + return FakeRenderer.prototype._nextSkinId++; + }; + + vm.attachRenderer(new FakeRenderer()); + + return vm.loadProject(project).then(() => vm.addSprite(sprite)); +}); + +const test = tap.test; + +test('load sprite3 with corrupted vector costume file', t => { + t.equal(vm.runtime.targets.length, 3); + + const stage = vm.runtime.targets[0]; + t.ok(stage.isStage); + + const blueGuySprite = vm.runtime.targets[2]; + t.equal(blueGuySprite.getName(), 'Blue Square Guy'); + t.equal(blueGuySprite.getCostumes().length, 1); + + const corruptedCostume = blueGuySprite.getCostumes()[0]; + t.equal(corruptedCostume.name, 'costume1'); + t.equal(corruptedCostume.assetId, defaultVectorAssetId); + t.equal(corruptedCostume.dataFormat, 'svg'); + // Runtime should have info about broken asset + t.ok(corruptedCostume.broken); + t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + // Verify that we saved the original asset data + t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); + + t.end(); +}); + +test('load and then save sprite with corrupted costume file', t => { + const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); + + t.equal(resavedSprite.name, 'Blue Square Guy'); + t.equal(resavedSprite.costumes.length, 1); + + const corruptedCostume = resavedSprite.costumes[0]; + t.equal(corruptedCostume.name, 'costume1'); + // Resaved project costume should have the metadata that corresponds to the original broken costume + t.equal(corruptedCostume.assetId, brokenCostumeMd5); + t.equal(corruptedCostume.dataFormat, 'svg'); + // Test that we didn't save any data about the costume being broken + t.notOk(corruptedCostume.broken); + + t.end(); +}); + +test('serializeCostume saves orignal broken costume', t => { + const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[2].id); + t.equal(costumeDescs.length, 1); + const costume = costumeDescs[0]; + t.equal(costume.fileName, `${brokenCostumeMd5}.svg`); + t.equal(md5(costume.fileContent), brokenCostumeMd5); + t.end(); + process.nextTick(process.exit); +}); diff --git a/test/integration/sprite3_missing_svg.js b/test/integration/sprite3_missing_svg.js new file mode 100644 index 000000000..70e3ab046 --- /dev/null +++ b/test/integration/sprite3_missing_svg.js @@ -0,0 +1,85 @@ +/** + * This test ensures that the VM gracefully handles a sprite3 file with + * a missing vector costume. The VM should handle this safely by displaying + * a Gray Question Mark, but keeping track of the original costume data + * and serializing the original costume data back out. The saved project.json + * should not reflect that the costume is broken and should therefore re-attempt + * to load the costume if the saved project is re-loaded. + */ +const path = require('path'); +const tap = require('tap'); +const makeTestStorage = require('../fixtures/make-test-storage'); +const FakeRenderer = require('../fixtures/fake-renderer'); +const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; +const VirtualMachine = require('../../src/index'); + +// The particular project that we're loading doesn't matter for this test +const projectUri = path.resolve(__dirname, '../fixtures/default.sb3'); +const project = readFileToBuffer(projectUri); + +const spriteUri = path.resolve(__dirname, '../fixtures/missing_svg.sprite3'); +const sprite = readFileToBuffer(spriteUri); + +const missingCostumeAssetId = 'a267f8b97ee9cf8aa9832aa0b4cfd9eb'; + +let vm; + +tap.beforeEach(() => { + const storage = makeTestStorage(); + + // This line removes the webhelper from the list of available helpers. + // W/o the following line, this fails because storage doesn't handle the case + // where none of the tools have isGetSupported: true + // TODO: Remove this line when the related storage bug is resolved so that + // storage gracefully handles non-browser situations where assets are missing. + storage._helpers = [storage._helpers[0]]; + + vm = new VirtualMachine(); + vm.attachStorage(storage); + vm.attachRenderer(new FakeRenderer()); + + return vm.loadProject(project).then(() => vm.addSprite(sprite)); +}); + +const test = tap.test; + +test('loading sprite3 with missing vector costume file', t => { + t.equal(vm.runtime.targets.length, 3); + + const stage = vm.runtime.targets[0]; + t.ok(stage.isStage); + + const blueGuySprite = vm.runtime.targets[2]; + t.equal(blueGuySprite.getName(), 'Blue Square Guy'); + t.equal(blueGuySprite.getCostumes().length, 1); + + const missingCostume = blueGuySprite.getCostumes()[0]; + t.equal(missingCostume.name, 'costume1'); + // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data + const defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageVector; + t.equal(missingCostume.assetId, defaultVectorAssetId); + t.equal(missingCostume.dataFormat, 'svg'); + // Runtime should have info about broken asset + t.ok(missingCostume.broken); + t.equal(missingCostume.broken.assetId, missingCostumeAssetId); + + t.end(); +}); + +test('load and then save sprite3 with missing vector costume file', t => { + const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); + + t.equal(resavedSprite.name, 'Blue Square Guy'); + t.equal(resavedSprite.costumes.length, 1); + + const missingCostume = resavedSprite.costumes[0]; + t.equal(missingCostume.name, 'costume1'); + // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data + t.equal(missingCostume.assetId, missingCostumeAssetId); + t.equal(missingCostume.dataFormat, 'svg'); + // Test that we didn't save any data about the costume being broken + t.notOk(missingCostume.broken); + + t.end(); + process.nextTick(process.exit); +});