diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html index 06c81a014..bf3cf3aba 100644 --- a/tests/jsunit/index.html +++ b/tests/jsunit/index.html @@ -22,7 +22,6 @@ - diff --git a/tests/jsunit/workspace_test.js b/tests/jsunit/workspace_test.js deleted file mode 100644 index 985da6a37..000000000 --- a/tests/jsunit/workspace_test.js +++ /dev/null @@ -1,301 +0,0 @@ -/** - * @license - * Copyright 2012 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - - -var workspace; -var mockControl_; - -function workspaceTest_setUp() { - defineGetVarBlock(); - workspace = new Blockly.Workspace(); -} - -function workspaceTest_tearDown() { - undefineGetVarBlock(); - if (mockControl_) { - mockControl_.restore(); - } - workspace.dispose(); -} - -function test_getWorkspaceById() { - var workspaceA = new Blockly.Workspace(); - var workspaceB = new Blockly.Workspace(); - try { - assertEquals('Find workspaceA.', workspaceA, - Blockly.Workspace.getById(workspaceA.id)); - assertEquals('Find workspaceB.', workspaceB, - Blockly.Workspace.getById(workspaceB.id)); - assertEquals('No workspace found.', null, - Blockly.Workspace.getById('I do not exist.')); - workspaceA.dispose(); - assertEquals('Can\'t find workspaceA.', null, - Blockly.Workspace.getById(workspaceA.id)); - assertEquals('WorkspaceB exists.', workspaceB, - Blockly.Workspace.getById(workspaceB.id)); - } finally { - workspaceB.dispose(); - workspaceA.dispose(); - } -} - -function test_getBlockById() { - workspaceTest_setUp(); - try { - var blockA = workspace.newBlock(''); - var blockB = workspace.newBlock(''); - assertEquals('Find blockA.', blockA, workspace.getBlockById(blockA.id)); - assertEquals('Find blockB.', blockB, workspace.getBlockById(blockB.id)); - assertEquals('No block found.', null, - workspace.getBlockById('I do not exist.')); - blockA.dispose(); - assertEquals('Can\'t find blockA.', null, workspace.getBlockById(blockA.id)); - assertEquals('BlockB exists.', blockB, workspace.getBlockById(blockB.id)); - workspace.clear(); - assertEquals('Can\'t find blockB.', null, workspace.getBlockById(blockB.id)); - } finally { - workspaceTest_tearDown(); - } -} - -function test_deleteVariable_InternalTrivial() { - workspaceTest_setUp(); - var var_1 = workspace.createVariable('name1', 'type1', 'id1'); - workspace.createVariable('name2', 'type2', 'id2'); - createMockVarBlock(workspace, 'id1'); - createMockVarBlock(workspace, 'id1'); - createMockVarBlock(workspace, 'id2'); - - var uses = workspace.getVariableUsesById(var_1.getId()); - workspace.deleteVariableInternal_(var_1, uses); - - var variable = workspace.getVariableById('id1'); - var block_var_name = workspace.topBlocks_[0].getVarModels()[0].name; - assertNull(variable); - checkVariableValues(workspace, 'name2', 'type2', 'id2'); - assertEquals('name2', block_var_name); - workspaceTest_tearDown(); -} - -// TODO(marisaleung): Test the alert for deleting a variable that is a procedure. - -function test_addTopBlock_TrivialFlyoutIsTrue() { - workspaceTest_setUp(); - var targetWorkspace = new Blockly.Workspace(); - workspace.isFlyout = true; - workspace.targetWorkspace = targetWorkspace; - targetWorkspace.createVariable('name1', '', '1'); - - // Flyout.init usually does this binding. - workspace.variableMap_ = targetWorkspace.getVariableMap(); - - try { - var block = createMockVarBlock(workspace, '1'); - workspace.removeTopBlock(block); - workspace.addTopBlock(block); - checkVariableValues(workspace, 'name1', '', '1'); - } finally { - workspaceTest_tearDown(); - // Have to dispose of the main workspace after the flyout workspace, because - // it holds the variable map. - // Normally the main workspace disposes of the flyout workspace. - targetWorkspace.dispose(); - } -} - -function test_clear_Trivial() { - workspaceTest_setUp(); - workspace.createVariable('name1', 'type1', 'id1'); - workspace.createVariable('name2', 'type2', 'id2'); - mockControl_ = setUpMockMethod(Blockly.Events, 'setGroup', [true, false], - null); - - try { - workspace.clear(); - var topBlocks_length = workspace.topBlocks_.length; - var varMapLength = Object.keys(workspace.variableMap_.variableMap_).length; - assertEquals(0, topBlocks_length); - assertEquals(0, varMapLength); - } finally { - workspaceTest_tearDown(); - } -} - -function test_clear_NoVariables() { - workspaceTest_setUp(); - mockControl_ = setUpMockMethod(Blockly.Events, 'setGroup', [true, false], - null); - - try { - workspace.clear(); - var topBlocks_length = workspace.topBlocks_.length; - var varMapLength = Object.keys(workspace.variableMap_.variableMap_).length; - assertEquals(0, topBlocks_length); - assertEquals(0, varMapLength); - } finally { - workspaceTest_tearDown(); - } -} - -function test_renameVariable_NoReference() { - // Test renaming a variable in the simplest case: when no blocks refer to it. - workspaceTest_setUp(); - var id = 'id1'; - var type = 'type1'; - var oldName = 'name1'; - var newName = 'name2'; - workspace.createVariable(oldName, type, id); - - try { - workspace.renameVariableById(id, newName); - checkVariableValues(workspace, newName, type, id); - // Renaming should not have created a new variable. - assertEquals(1, workspace.getAllVariables().length); - } finally { - workspaceTest_tearDown(); - } -} - -function test_renameVariable_ReferenceExists() { - // Test renaming a variable when a reference to it exists. - // Expect 'renameVariable' to change oldName variable name to newName. - workspaceTest_setUp(); - var newName = 'name2'; - - createVariableAndBlock(workspace); - - workspace.renameVariableById('id1', newName); - checkVariableValues(workspace, newName, 'type1', 'id1'); - // Renaming should not have created a new variable. - assertEquals(1, workspace.getAllVariables().length); - var block_var_name = workspace.topBlocks_[0].getVarModels()[0].name; - assertEquals(newName, block_var_name); - workspaceTest_tearDown(); -} - -function test_renameVariable_TwoVariablesSameType() { - // Expect 'renameVariable' to change oldName variable name to newName. - // Expect oldName block name to change to newName - workspaceTest_setUp(); - var id1 = 'id1'; - var id2 = 'id2'; - var type = 'type1'; - - var oldName = 'name1'; - var newName = 'name2'; - // Create two variables of the same type. - workspace.createVariable(oldName, type, id1); - workspace.createVariable(newName, type, id2); - // Create blocks to refer to both of them. - createMockVarBlock(workspace, id1); - createMockVarBlock(workspace, id2); - - workspace.renameVariableById(id1, newName); - checkVariableValues(workspace, newName, type, id2); - // The old variable should have been deleted. - var variable = workspace.getVariableById(id1); - assertNull(variable); - - // There should only be one variable left. - assertEquals(1, workspace.getAllVariables().length); - - // References should have the correct names. - var block_var_name_1 = workspace.topBlocks_[0].getVarModels()[0].name; - var block_var_name_2 = workspace.topBlocks_[1].getVarModels()[0].name; - assertEquals(newName, block_var_name_1); - assertEquals(newName, block_var_name_2); - - workspaceTest_tearDown(); -} - -function test_renameVariable_TwoVariablesDifferentType() { - // Expect the rename to succeed, because variables with different types are - // allowed to have the same name. - workspaceTest_setUp(); - createTwoVariablesAndBlocks(workspace); - - var newName = 'name2'; - workspace.renameVariableById('id1', newName); - - checkVariableValues(workspace, newName, 'type1', 'id1'); - checkVariableValues(workspace, newName, 'type2', 'id2'); - - // References shoul have the correct names. - var block_var_name_1 = workspace.topBlocks_[0].getVarModels()[0].name; - var block_var_name_2 = workspace.topBlocks_[1].getVarModels()[0].name; - assertEquals(newName, block_var_name_1); - assertEquals(newName, block_var_name_2); - - workspaceTest_tearDown(); -} - -function test_renameVariable_OldCase() { - // Rename a variable with a single reference. Update only the capitalization. - workspaceTest_setUp(); - var newName = 'Name1'; - - createVariableAndBlock(workspace); - - workspace.renameVariableById('id1', newName); - checkVariableValues(workspace, newName, 'type1', 'id1'); - var variable = workspace.getVariableById('id1'); - assertNotEquals('name1', variable.name); - workspaceTest_tearDown(); -} - -function test_renameVariable_TwoVariablesAndOldCase() { - // Test renaming a variable to an in-use name, but with different - // capitalization. The new capitalization should apply everywhere. - - // TODO (fenichel): What about different capitalization but also different - // types? - workspaceTest_setUp(); - var oldName = 'name1'; - var oldCase = 'Name2'; - var newName = 'name2'; - - var id1 = 'id1'; - var id2 = 'id2'; - - var type = 'type1'; - - workspace.createVariable(oldName, type, id1); - workspace.createVariable(oldCase, type, id2); - createMockVarBlock(workspace, id1); - createMockVarBlock(workspace, id2); - - workspace.renameVariableById(id1, newName); - - checkVariableValues(workspace, newName, type, id2); - - // The old variable should have been deleted. - var variable = workspace.getVariableById(id1); - assertNull(variable); - - // There should only be one variable left. - assertEquals(1, workspace.getAllVariables().length); - - // Blocks should now use the new capitalization. - var block_var_name_1 = workspace.topBlocks_[0].getVarModels()[0].name; - var block_var_name_2 = workspace.topBlocks_[1].getVarModels()[0].name; - assertEquals(newName, block_var_name_1); - assertEquals(newName, block_var_name_2); - workspaceTest_tearDown(); -} - -function test_deleteVariableById_Trivial() { - workspaceTest_setUp(); - createTwoVariablesAndBlocks(workspace); - - workspace.deleteVariableById('id1'); - checkVariableValues(workspace, 'name2', 'type2', 'id2'); - var variable = workspace.getVariableById('id1'); - var block_var_name = workspace.topBlocks_[0].getVarModels()[0].name; - assertNull(variable); - assertEquals('name2', block_var_name); - workspaceTest_tearDown(); -} diff --git a/tests/mocha/workspace_test.js b/tests/mocha/workspace_test.js index 42359bbfd..43066c830 100644 --- a/tests/mocha/workspace_test.js +++ b/tests/mocha/workspace_test.js @@ -23,6 +23,287 @@ suite('Workspace', function() { teardown(function() { delete Blockly.Blocks['get_var_block']; this.workspace.dispose(); + // Clear Blockly.Event state. + Blockly.Events.setGroup(false); + Blockly.Events.disabled_ = 0; + sinon.restore(); + }); + + suite('clear', function() { + test('Trivial', function() { + sinon.stub(Blockly.Events, "setGroup").returns(null); + this.workspace.createVariable('name1', 'type1', 'id1'); + this.workspace.createVariable('name2', 'type2', 'id2'); + this.workspace.newBlock(''); + + this.workspace.clear(); + chai.assert.equal(this.workspace.topBlocks_.length, 0); + var varMapLength = + Object.keys(this.workspace.variableMap_.variableMap_).length; + chai.assert.equal(varMapLength, 0); + }); + + test('No variables', function() { + sinon.stub(Blockly.Events, "setGroup").returns(null); + this.workspace.newBlock(''); + + this.workspace.clear(); + chai.assert.equal(this.workspace.topBlocks_.length, 0); + var varMapLength = + Object.keys(this.workspace.variableMap_.variableMap_).length; + chai.assert.equal(varMapLength, 0); + }); + }); + + suite('deleteVariable', function() { + setup(function() { + // Create two variables of different types. + this.var1 = this.workspace.createVariable('name1', 'type1', 'id1'); + this.var2 = this.workspace.createVariable('name2', 'type2', 'id2'); + // Create blocks to refer to both of them. + // Turn off events to avoid testing XML at the same time. + Blockly.Events.disable(); + var block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id1'); + block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id1'); + block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id2'); + Blockly.Events.enable(); + }); + + test('deleteVariableInternal_', function() { + var uses = this.workspace.getVariableUsesById(this.var1.getId()); + this.workspace.deleteVariableInternal_(this.var1, uses); + + var variable = this.workspace.getVariableById('id1'); + chai.assert.isNull(variable); + var blockVarName = this.workspace.topBlocks_[0].getVarModels()[0].name; + assertVariableValues(this.workspace, 'name2', 'type2', 'id2'); + chai.assert.equal(blockVarName, 'name2'); + }); + + test('deleteVariableById one usage', function() { + // Deleting variable one usage should not trigger confirm dialog. + var stub = + sinon.stub(Blockly, "confirm").callsArgWith(1, true); + this.workspace.deleteVariableById('id2'); + + sinon.assert.notCalled(stub); + var variable = this.workspace.getVariableById('id2'); + chai.assert.isNull(variable); + assertVariableValues(this.workspace, 'name1', 'type1', 'id1'); + var blockVarName = this.workspace.topBlocks_[0].getVarModels()[0].name; + chai.assert.equal(blockVarName, 'name1'); + }); + + test('deleteVariableById multiple usages confirm', function() { + // Deleting variable with multiple usages triggers confirm dialog. + var stub = + sinon.stub(Blockly, "confirm").callsArgWith(1, true); + this.workspace.deleteVariableById('id1'); + + sinon.assert.calledOnce(stub); + var variable = this.workspace.getVariableById('id1'); + chai.assert.isNull(variable); + assertVariableValues(this.workspace, 'name2', 'type2', 'id2'); + var blockVarName = this.workspace.topBlocks_[0].getVarModels()[0].name; + chai.assert.equal(blockVarName, 'name2'); + }); + + test('deleteVariableById multiple usages cancel', function() { + // Deleting variable with multiple usages triggers confirm dialog. + var stub = + sinon.stub(Blockly, "confirm").callsArgWith(1, false); + this.workspace.deleteVariableById('id1'); + + sinon.assert.calledOnce(stub); + assertVariableValues(this.workspace, 'name1', 'type1', 'id1'); + assertVariableValues(this.workspace, 'name2', 'type2', 'id2'); + var blockVarName1 = this.workspace.topBlocks_[0].getVarModels()[0].name; + chai.assert.equal(blockVarName1, 'name1'); + var blockVarName2 = this.workspace.topBlocks_[1].getVarModels()[0].name; + chai.assert.equal(blockVarName2, 'name1'); + var blockVarName3 = this.workspace.topBlocks_[2].getVarModels()[0].name; + chai.assert.equal(blockVarName3, 'name2'); + }); + }); + + suite('renameVariable', function() { + setup(function() { + this.workspace.createVariable('name1', 'type1', 'id1'); + }); + test('No references', function() { + this.workspace.renameVariableById('id1', 'name2'); + assertVariableValues(this.workspace, 'name2', 'type1', 'id1'); + // Renaming should not have created a new variable. + chai.assert.equal(this.workspace.getAllVariables().length, 1); + }); + + test('Reference exists', function() { + // Turn off events to avoid testing XML at the same time. + Blockly.Events.disable(); + var block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id1'); + Blockly.Events.enable(); + + this.workspace.renameVariableById('id1', 'name2'); + assertVariableValues(this.workspace, 'name2', 'type1', 'id1'); + // Renaming should not have created a new variable. + chai.assert.equal(this.workspace.getAllVariables().length, 1); + var blockVarName = this.workspace.topBlocks_[0].getVarModels()[0].name; + chai.assert.equal(blockVarName, 'name2'); + }); + + test('Reference exists different capitalizations', function() { + // Turn off events to avoid testing XML at the same time. + Blockly.Events.disable(); + var block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id1'); + Blockly.Events.enable(); + + this.workspace.renameVariableById('id1', 'Name1'); + assertVariableValues(this.workspace, 'Name1', 'type1', 'id1'); + // Renaming should not have created a new variable. + chai.assert.equal(this.workspace.getAllVariables().length, 1); + var blockVarName = this.workspace.topBlocks_[0].getVarModels()[0].name; + chai.assert.equal(blockVarName, 'Name1'); + }); + + suite('Two variables rename overlap', function() { + test('Same type', function() { + this.workspace.createVariable('name2', 'type1', 'id2'); + // Turn off events to avoid testing XML at the same time. + Blockly.Events.disable(); + var block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id1'); + block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id2'); + Blockly.Events.enable(); + + this.workspace.renameVariableById('id1', 'name2'); + + // The second variable should remain unchanged. + assertVariableValues(this.workspace, 'name2', 'type1', 'id2'); + // The first variable should have been deleted. + var variable = this.workspace.getVariableById('id1'); + chai.assert.isNull(variable); + // There should only be one variable left. + chai.assert.equal(this.workspace.getAllVariables().length, 1); + + // Both blocks should now reference variable with name2. + var blockVar1 = this.workspace.topBlocks_[0].getVarModels()[0].name; + chai.assert.equal(blockVar1, 'name2'); + var blockVar2 = this.workspace.topBlocks_[1].getVarModels()[0].name; + chai.assert.equal(blockVar2, 'name2'); + }); + + test('Different type', function() { + this.workspace.createVariable('name2', 'type2', 'id2'); + // Turn off events to avoid testing XML at the same time. + Blockly.Events.disable(); + var block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id1'); + block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id2'); + Blockly.Events.enable(); + + this.workspace.renameVariableById('id1', 'name2'); + + // Variables with different type are allowed to have the same name. + assertVariableValues(this.workspace, 'name2', 'type1', 'id1'); + assertVariableValues(this.workspace, 'name2', 'type2', 'id2'); + + // Both blocks should now reference variable with name2. + var blockVar1 = this.workspace.topBlocks_[0].getVarModels()[0].name; + chai.assert.equal(blockVar1, 'name2'); + var blockVar2 = this.workspace.topBlocks_[1].getVarModels()[0].name; + chai.assert.equal(blockVar2, 'name2'); + }); + + test('Same type different capitalization', function() { + this.workspace.createVariable('name2', 'type1', 'id2'); + // Turn off events to avoid testing XML at the same time. + Blockly.Events.disable(); + var block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id1'); + block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id2'); + Blockly.Events.enable(); + + this.workspace.renameVariableById('id1', 'Name2'); + + // The second variable should be updated. + assertVariableValues(this.workspace, 'Name2', 'type1', 'id2'); + // The first variable should have been deleted. + var variable = this.workspace.getVariableById('id1'); + chai.assert.isNull(variable); + // There should only be one variable left. + chai.assert.equal(this.workspace.getAllVariables().length, 1); + + // Both blocks should now reference variable with Name2. + var blockVar1 = this.workspace.topBlocks_[0].getVarModels()[0].name; + chai.assert.equal(blockVar1, 'Name2'); + var blockVar2 = this.workspace.topBlocks_[1].getVarModels()[0].name; + chai.assert.equal(blockVar2, 'Name2'); + }); + + test('Different type different capitalization', function() { + this.workspace.createVariable('name2', 'type2', 'id2'); + // Turn off events to avoid testing XML at the same time. + Blockly.Events.disable(); + var block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id1'); + block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('id2'); + Blockly.Events.enable(); + + this.workspace.renameVariableById('id1', 'Name2'); + + // Variables with different type are allowed to have the same name. + assertVariableValues(this.workspace, 'Name2', 'type1', 'id1'); + // Second variable should remain unchanged. + assertVariableValues(this.workspace, 'name2', 'type2', 'id2'); + + // Only first block should use new capitalization. + var blockVar1 = this.workspace.topBlocks_[0].getVarModels()[0].name; + chai.assert.equal(blockVar1, 'Name2'); + var blockVar2 = this.workspace.topBlocks_[1].getVarModels()[0].name; + chai.assert.equal(blockVar2, 'name2'); + }); + }); + }); + + suite('addTopBlock', function() { + setup(function() { + this.targetWorkspace = new Blockly.Workspace(); + this.workspace.isFlyout = true; + this.workspace.targetWorkspace = this.targetWorkspace; + }); + + teardown(function() { + // Have to dispose of the main workspace after the flyout workspace + // because it holds the variable map. + // Normally the main workspace disposes of the flyout workspace. + this.targetWorkspace.dispose(); + }); + + test('Trivial Flyout is True', function() { + this.targetWorkspace.createVariable('name1', '', '1'); + + // Flyout.init usually does this binding. + this.workspace.variableMap_ = this.targetWorkspace.getVariableMap(); + + // Turn off events to avoid testing XML at the same time. + Blockly.Events.disable(); + var block = new Blockly.Block(this.workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue('1'); + Blockly.Events.enable(); + + this.workspace.removeTopBlock(block); + this.workspace.addTopBlock(block); + assertVariableValues(this.workspace, 'name1', '', '1'); + }); }); suite('getTopBlocks(ordered=true)', function() { @@ -354,4 +635,73 @@ suite('Workspace', function() { }); }); + suite('getById', function() { + setup(function() { + this.workspaceB = new Blockly.Workspace(); + }); + + teardown(function() { + this.workspaceB.dispose(); + }); + + test('Trivial', function() { + chai.assert.equal(Blockly.Workspace.getById( + this.workspace.id), this.workspace, 'Find workspace'); + chai.assert.equal(Blockly.Workspace.getById( + this.workspaceB.id), this.workspaceB, 'Find workspaceB'); + }); + + test('Null id', function() { + chai.assert.isNull(Blockly.Workspace.getById(null)); + }); + + test('Non-existent id', function() { + chai.assert.isNull(Blockly.Workspace.getById('badId')); + }); + + test('After dispose', function() { + this.workspaceB.dispose(); + chai.assert.isNull(Blockly.Workspace.getById(this.workspaceB.id)); + }); + }); + + suite('getBlockById', function() { + setup(function() { + this.blockA = this.workspace.newBlock(''); + this.blockB = this.workspace.newBlock(''); + this.workspaceB = new Blockly.Workspace(); + }); + + teardown(function() { + this.workspaceB.dispose(); + }); + + test('Trivial', function() { + chai.assert.equal( + this.workspace.getBlockById(this.blockA.id),this.blockA); + chai.assert.equal( + this.workspace.getBlockById(this.blockB.id), this.blockB); + }); + + test('Null id', function() { + chai.assert.isNull(this.workspace.getBlockById(null)); + }); + + test('Non-existent id', function() { + chai.assert.isNull(this.workspace.getBlockById('badId')); + }); + + test('After dispose', function() { + this.blockA.dispose(); + chai.assert.isNull(this.workspace.getBlockById(this.blockA)); + chai.assert.equal( + this.workspace.getBlockById(this.blockB.id), this.blockB); + }); + + test('After clear', function() { + this.workspace.clear(); + chai.assert.isNull(this.workspace.getBlockById(this.blockA)); + chai.assert.isNull(this.workspace.getBlockById(this.blockB)); + }); + }); });