diff --git a/test/fixtures/cat.sprite2 b/test/fixtures/cat.sprite2 new file mode 100644 index 000000000..9339b8e6f Binary files /dev/null and b/test/fixtures/cat.sprite2 differ diff --git a/test/fixtures/cat.sprite3 b/test/fixtures/cat.sprite3 new file mode 100644 index 000000000..8a5890c1d Binary files /dev/null and b/test/fixtures/cat.sprite3 differ diff --git a/test/integration/running_project_changed_state.js b/test/integration/running_project_changed_state.js new file mode 100644 index 000000000..1af086d56 --- /dev/null +++ b/test/integration/running_project_changed_state.js @@ -0,0 +1,48 @@ +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/looks.sb2'); +const project = readFileToBuffer(uri); + +test('Running project should not emit project changed event', t => { + const vm = new VirtualMachine(); + vm.attachStorage(makeTestStorage()); + + let projectChanged = false; + vm.on('PROJECT_CHANGED', () => { + projectChanged = true; + }); + + // Evaluate playground data and exit + vm.on('playgroundData', () => { + t.equal(projectChanged, false); + t.end(); + process.nextTick(process.exit); + }); + + // Start VM, load project, and run + t.doesNotThrow(() => { + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + vm.loadProject(project).then(() => { + // The test in unit/project_load_changed_state.js tests + // that loading a project does not emit a project changed + // event. This setup tries to be agnostic of whether that + // test is passing or failing. + projectChanged = false; + + vm.greenFlag(); + + // After two seconds, get playground data and stop + setTimeout(() => { + vm.getPlaygroundData(); + vm.stopAll(); + }, 2000); + }); + }); +}); diff --git a/test/unit/project_changed_state.js b/test/unit/project_changed_state.js new file mode 100644 index 000000000..d0d1c801b --- /dev/null +++ b/test/unit/project_changed_state.js @@ -0,0 +1,240 @@ +const tap = require('tap'); +const path = require('path'); +const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; +const makeTestStorage = require('../fixtures/make-test-storage'); +const VirtualMachine = require('../../src/virtual-machine'); + +let vm; +let projectChanged; + +tap.beforeEach(() => { + const projectUri = path.resolve(__dirname, '../fixtures/default.sb2'); + const project = readFileToBuffer(projectUri); + + vm = new VirtualMachine(); + + vm.runtime.addListener('PROJECT_CHANGED', () => { + projectChanged = true; + }); + + vm.attachStorage(makeTestStorage()); + return vm.loadProject(project).then(() => { + // The test in project_load_changed_state.js tests + // that loading a project does not emit a project changed + // event. This setup tries to be agnostic of whether that + // test is passing or failing. + projectChanged = false; + }); +}); + +tap.tearDown(() => process.nextTick(process.exit)); + +const test = tap.test; + +test('Adding a sprite (from sprite2) should emit a project changed event', t => { + const sprite2Uri = path.resolve(__dirname, '../fixtures/cat.sprite2'); + const sprite2 = readFileToBuffer(sprite2Uri); + + vm.addSprite(sprite2).then(() => { + t.equal(projectChanged, true); + t.end(); + }); +}); + +test('Adding a sprite (from sprite3) should emit a project changed event', t => { + const sprite3Uri = path.resolve(__dirname, '../fixtures/cat.sprite3'); + const sprite3 = readFileToBuffer(sprite3Uri); + + vm.addSprite(sprite3).then(() => { + t.equal(projectChanged, true); + t.end(); + }); +}); + +test('Adding a costume should emit a project changed event', t => { + const newCostume = { + name: 'costume1', + baseLayerID: 0, + baseLayerMD5: 'f9a1c175dbe2e5dee472858dd30d16bb.svg', + bitmapResolution: 1, + rotationCenterX: 47, + rotationCenterY: 55 + }; + + vm.addCostume('f9a1c175dbe2e5dee472858dd30d16bb.svg', newCostume).then(() => { + t.equal(projectChanged, true); + t.end(); + }); +}); + +test('Adding a costume from library should emit a project changed event', t => { + const newCostume = { + name: 'costume1', + baseLayerID: 0, + baseLayerMD5: 'f9a1c175dbe2e5dee472858dd30d16bb.svg', + bitmapResolution: 1, + rotationCenterX: 47, + rotationCenterY: 55 + }; + + vm.addCostumeFromLibrary('f9a1c175dbe2e5dee472858dd30d16bb.svg', newCostume).then(() => { + t.equal(projectChanged, true); + t.end(); + }); +}); + +test('Adding a backdrop should emit a project changed event', t => { + const newCostume = { + name: 'costume1', + baseLayerID: 0, + baseLayerMD5: 'f9a1c175dbe2e5dee472858dd30d16bb.svg', + bitmapResolution: 1, + rotationCenterX: 47, + rotationCenterY: 55 + }; + + vm.addBackdrop('f9a1c175dbe2e5dee472858dd30d16bb.svg', newCostume).then(() => { + t.equal(projectChanged, true); + t.end(); + }); +}); + +test('Adding a sound should emit a project changed event', t => { + const newSound = { + soundName: 'meow', + soundID: 0, + md5: '83c36d806dc92327b9e7049a565c6bff.wav', + sampleCount: 18688, + rate: 22050 + }; + + vm.addSound(newSound).then(() => { + t.equal(projectChanged, true); + t.end(); + }); +}); + +test('Deleting a sprite should emit a project changed event', t => { + const spriteId = vm.editingTarget.id; + + vm.deleteSprite(spriteId); + t.equal(projectChanged, true); + t.end(); +}); + +test('Deleting a costume should emit a project changed event', t => { + vm.deleteCostume(0); + + t.equal(projectChanged, true); + t.end(); +}); + +test('Deleting a sound should emit a project changed event', t => { + vm.deleteSound(0); + + t.equal(projectChanged, true); + t.end(); +}); + +test('Reordering a sprite should emit a project changed event', t => { + const sprite3Uri = path.resolve(__dirname, '../fixtures/cat.sprite3'); + const sprite3 = readFileToBuffer(sprite3Uri); + + // Add a new sprite so we have 2 to reorder + vm.addSprite(sprite3).then(() => { + // Reset the project changed flag to ignore change from adding new sprite + projectChanged = false; + t.equal(vm.runtime.targets.filter(target => !target.isStage).length, 2); + vm.reorderTarget(2, 1); + t.equal(projectChanged, true); + t.end(); + }); +}); + +test('Reordering a costume should emit a project changed event', t => { + t.equal(vm.editingTarget.sprite.costumes.length, 2); + const spriteId = vm.editingTarget.id; + vm.reorderCostume(spriteId, 2, 1); + t.equal(projectChanged, true); + t.end(); +}); + +test('Reordering a sound should emit a project changed event', t => { + const spriteId = vm.editingTarget.id; + const newSound = { + soundName: 'meow', + soundID: 0, + md5: '83c36d806dc92327b9e7049a565c6bff.wav', + sampleCount: 18688, + rate: 22050 + }; + vm.addSound(newSound).then(() => { + // Reset the project changed flag to ignore change from adding new sound + projectChanged = false; + t.equal(vm.editingTarget.sprite.sounds.length, 2); + vm.reorderSound(spriteId, 2, 1); + t.equal(projectChanged, true); + t.end(); + }); +}); + +test('Renaming a sprite should emit a project changed event', t => { + const spriteId = vm.editingTarget.id; + vm.renameSprite(spriteId, 'My Sprite'); + t.equal(projectChanged, true); + t.end(); +}); + +test('Renaming a costume should emit a project changed event', t => { + vm.renameCostume(0, 'My Costume'); + t.equal(projectChanged, true); + t.end(); +}); + +test('Renaming a sound should emit a project changed event', t => { + vm.renameSound(0, 'My Sound'); + + t.equal(projectChanged, true); + t.end(); +}); + +test('Changing sprite info should emit a project changed event', t => { + const newSpritePosition = { + x: 10, + y: 100 + }; + + vm.postSpriteInfo(newSpritePosition); + t.equal(projectChanged, true); + projectChanged = false; + + const newSpriteDirection = { + direction: -30 + }; + + vm.postSpriteInfo(newSpriteDirection); + t.equal(projectChanged, true); + projectChanged = false; + + t.end(); + +}); + +test('Editing a vector costume should emit a project changed event', t => { + const mockSvg = 'svg'; + const mockRotationX = -13; + const mockRotationY = 25; + + vm.updateSvg(0, mockSvg, mockRotationX, mockRotationY); + t.equal(projectChanged, true); + t.end(); +}); + +test('Editing a sound should emit a project changed event', t => { + const mockSoundBuffer = []; + const mockSoundEncoding = []; + + vm.updateSoundBuffer(0, mockSoundBuffer, mockSoundEncoding); + t.equal(projectChanged, true); + t.end(); +}); diff --git a/test/unit/project_load_changed_state.js b/test/unit/project_load_changed_state.js new file mode 100644 index 000000000..0f510ef41 --- /dev/null +++ b/test/unit/project_load_changed_state.js @@ -0,0 +1,30 @@ +const tap = require('tap'); +const path = require('path'); +const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; +const makeTestStorage = require('../fixtures/make-test-storage'); +const VirtualMachine = require('../../src/virtual-machine'); + +tap.tearDown(() => process.nextTick(process.exit)); + +const test = tap.test; + +// Test that loading a project does not emit a project change +// This is in its own file so that it does not affect the test setup +// and results of the other project changed state tests +test('Loading a project should not emit a project changed event', t => { + const projectUri = path.resolve(__dirname, '../fixtures/default.sb2'); + const project = readFileToBuffer(projectUri); + + const vm = new VirtualMachine(); + + let projectChanged = false; + vm.runtime.addListener('PROJECT_CHANGED', () => { + projectChanged = true; + }); + + vm.attachStorage(makeTestStorage()); + return vm.loadProject(project).then(() => { + t.equal(projectChanged, false); + t.end(); + }); +});