Files
blockly/tests/mocha/blocks/variables_test.js
Tasheena a481253bb4 refactor(VariableMap): Stop using deprecated wrapper methods (#9340)
* refactor(VariableMap): Stop using deprecated wrapper methods

* fix format

* fix: Apply review suggestions

Co-authored-by: Christopher Allen <cpcallen+github@gmail.com>

* fix: restore blank line

---------

Co-authored-by: Christopher Allen <cpcallen+github@gmail.com>
2025-09-24 15:23:41 +00:00

312 lines
9.1 KiB
JavaScript

/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {nameUsedWithConflictingParam} from '../../../build/src/core/variables.js';
import {assert} from '../../../node_modules/chai/index.js';
import {
MockParameterModelWithVar,
MockProcedureModel,
} from '../test_helpers/procedures.js';
import {
sharedTestSetup,
sharedTestTeardown,
} from '../test_helpers/setup_teardown.js';
suite('Variables', function () {
setup(function () {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
Blockly.defineBlocksWithJsonArray([
{
'type': 'get_var_block',
'message0': '%1',
'args0': [
{
'type': 'field_variable',
'name': 'VAR',
'variableTypes': ['', 'type1', 'type2'],
},
],
},
]);
this.variableMap = this.workspace.getVariableMap();
this.variableMap.createVariable('foo', 'type1', '1');
this.variableMap.createVariable('bar', 'type1', '2');
this.variableMap.createVariable('baz', 'type1', '3');
});
teardown(function () {
sharedTestTeardown.call(this);
});
/**
* Create a test get_var_block.
* Will fail if get_var_block isn't defined.
* @param {!Blockly.Workspace} workspace The workspace on which to create the
* block.
* @param {!string} variableId The id of the variable to reference.
* @return {!Blockly.Block} The created block.
*/
function createTestVarBlock(workspace, variableId) {
// Turn off events to avoid testing XML at the same time.
Blockly.Events.disable();
const block = new Blockly.Block(workspace, 'get_var_block');
block.inputList[0].fieldRow[0].setValue(variableId);
Blockly.Events.enable();
return block;
}
suite('allUsedVarModels', function () {
test('All used', function () {
createTestVarBlock(this.workspace, '1');
createTestVarBlock(this.workspace, '2');
createTestVarBlock(this.workspace, '3');
const result = Blockly.Variables.allUsedVarModels(this.workspace);
assert.equal(
result.length,
3,
'Expected three variables in the list of used variables',
);
});
test('Some unused', function () {
createTestVarBlock(this.workspace, '2');
const result = Blockly.Variables.allUsedVarModels(this.workspace);
assert.equal(
result.length,
1,
'Expected one variable in the list of used variables',
);
assert.equal(
result[0].getId(),
'2',
'Expected variable with ID 2 in the list of used variables',
);
});
test('Var used twice', function () {
createTestVarBlock(this.workspace, '2');
createTestVarBlock(this.workspace, '2');
const result = Blockly.Variables.allUsedVarModels(this.workspace);
// Using the same variable multiple times should not change the number of
// elements in the list.
assert.equal(
result.length,
1,
'Expected one variable in the list of used variables',
);
assert.equal(
result[0].getId(),
'2',
'Expected variable with ID 2 in the list of used variables',
);
});
test('All unused', function () {
const result = Blockly.Variables.allUsedVarModels(this.workspace);
assert.equal(
result.length,
0,
'Expected no variables in the list of used variables',
);
});
});
suite('getVariable', function () {
test('By ID', function () {
const var1 = this.variableMap.createVariable('name1', 'type1', 'id1');
const var2 = this.variableMap.createVariable('name2', 'type1', 'id2');
const var3 = this.variableMap.createVariable('name3', 'type2', 'id3');
const result1 = Blockly.Variables.getVariable(this.workspace, 'id1');
const result2 = Blockly.Variables.getVariable(this.workspace, 'id2');
const result3 = Blockly.Variables.getVariable(this.workspace, 'id3');
assert.equal(var1, result1);
assert.equal(var2, result2);
assert.equal(var3, result3);
});
test('By name and type', function () {
const var1 = this.variableMap.createVariable('name1', 'type1', 'id1');
const var2 = this.variableMap.createVariable('name2', 'type1', 'id2');
const var3 = this.variableMap.createVariable('name3', 'type2', 'id3');
const result1 = Blockly.Variables.getVariable(
this.workspace,
null,
'name1',
'type1',
);
const result2 = Blockly.Variables.getVariable(
this.workspace,
null,
'name2',
'type1',
);
const result3 = Blockly.Variables.getVariable(
this.workspace,
null,
'name3',
'type2',
);
// Searching by name + type is correct.
assert.equal(var1, result1);
assert.equal(var2, result2);
assert.equal(var3, result3);
});
test('Bad ID with name and type fallback', function () {
const var1 = this.variableMap.createVariable('name1', 'type1', 'id1');
const var2 = this.variableMap.createVariable('name2', 'type1', 'id2');
const var3 = this.variableMap.createVariable('name3', 'type2', 'id3');
const result1 = Blockly.Variables.getVariable(
this.workspace,
'badId',
'name1',
'type1',
);
const result2 = Blockly.Variables.getVariable(
this.workspace,
'badId',
'name2',
'type1',
);
const result3 = Blockly.Variables.getVariable(
this.workspace,
'badId',
'name3',
'type2',
);
// Searching by ID failed, but falling back onto name + type is correct.
assert.equal(var1, result1);
assert.equal(var2, result2);
assert.equal(var3, result3);
});
});
suite('renaming variables creating conflicts', function () {
suite('renaming variables creating parameter conflicts', function () {
test('conflicts within legacy procedure blocks return the procedure name', function () {
Blockly.serialization.blocks.append(
{
'type': 'procedures_defnoreturn',
'extraState': {
'params': [
{
'name': 'x',
'id': '6l3P%Y!9EgA(Nh{E`Tl,',
},
{
'name': 'y',
'id': 'l1EtlJe%z_M[O-@uPAQ8',
},
],
},
'fields': {
'NAME': 'test name',
},
},
this.workspace,
);
assert.equal(
'test name',
nameUsedWithConflictingParam('x', 'y', this.workspace),
'Expected the name of the procedure with the conflicting ' +
'param to be returned',
);
});
test(
'if no legacy block has the old var name, no procedure ' +
'name is returned',
function () {
Blockly.serialization.blocks.append(
{
'type': 'procedures_defnoreturn',
'extraState': {
'params': [
{
'name': 'definitely not x',
'id': '6l3P%Y!9EgA(Nh{E`Tl,',
},
{
'name': 'y',
'id': 'l1EtlJe%z_M[O-@uPAQ8',
},
],
},
'fields': {
'NAME': 'test name',
},
},
this.workspace,
);
assert.isNull(
nameUsedWithConflictingParam('x', 'y', this.workspace),
'Expected there to be no conflict',
);
},
);
test('conflicts within procedure models return the procedure name', function () {
this.workspace
.getProcedureMap()
.add(
new MockProcedureModel('test name')
.insertParameter(
new MockParameterModelWithVar('x', this.workspace),
0,
)
.insertParameter(
new MockParameterModelWithVar('y', this.workspace),
0,
),
);
assert.equal(
'test name',
nameUsedWithConflictingParam('x', 'y', this.workspace),
'Expected the name of the procedure with the conflicting ' +
'param to be returned',
);
});
test(
'if no procedure model has the old var, no procedure ' +
'name is returned',
function () {
this.workspace
.getProcedureMap()
.add(
new MockProcedureModel('test name')
.insertParameter(
new MockParameterModelWithVar(
'definitely not x',
this.workspace,
),
0,
)
.insertParameter(
new MockParameterModelWithVar('y', this.workspace),
0,
),
);
assert.isNull(
nameUsedWithConflictingParam('x', 'y', this.workspace),
'Expected there to be no conflict',
);
},
);
});
});
});