Merge 06-22

This commit is contained in:
Paul Kaplan 2017-06-22 10:38:20 -04:00
parent bec631512e
commit fce962c0fc
31 changed files with 1553 additions and 364 deletions

View file

@ -182,7 +182,7 @@ Blockly.Block = function(workspace, prototypeName, opt_id) {
/** @type {boolean|undefined} */
this.inputsInlineDefault = this.inputsInline;
if (Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.Create(this));
Blockly.Events.fire(new Blockly.Events.BlockCreate(this));
}
// Bind an onchange function, if it exists.
if (goog.isFunction(this.onchange)) {
@ -235,7 +235,7 @@ Blockly.Block.prototype.dispose = function(healStack) {
}
this.unplug(healStack);
if (Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.Delete(this));
Blockly.Events.fire(new Blockly.Events.BlockDelete(this));
}
Blockly.Events.disable();
@ -957,7 +957,7 @@ Blockly.Block.prototype.setOutput = function(newBoolean, opt_check) {
*/
Blockly.Block.prototype.setInputsInline = function(newBoolean) {
if (this.inputsInline != newBoolean) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this, 'inline', null, this.inputsInline, newBoolean));
this.inputsInline = newBoolean;
}
@ -996,7 +996,7 @@ Blockly.Block.prototype.getInputsInline = function() {
*/
Blockly.Block.prototype.setDisabled = function(disabled) {
if (this.disabled != disabled) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this, 'disabled', null, this.disabled, disabled));
this.disabled = disabled;
}
@ -1033,7 +1033,7 @@ Blockly.Block.prototype.isCollapsed = function() {
*/
Blockly.Block.prototype.setCollapsed = function(collapsed) {
if (this.collapsed_ != collapsed) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this, 'collapsed', null, this.collapsed_, collapsed));
this.collapsed_ = collapsed;
}
@ -1629,7 +1629,7 @@ Blockly.Block.prototype.getCommentText = function() {
*/
Blockly.Block.prototype.setCommentText = function(text) {
if (this.comment != text) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this, 'comment', null, this.comment, text || ''));
this.comment = text;
}
@ -1719,7 +1719,7 @@ Blockly.Block.prototype.getRelativeToSurfaceXY = function() {
*/
Blockly.Block.prototype.moveBy = function(dx, dy) {
goog.asserts.assert(!this.parentBlock_, 'Block has parent.');
var event = new Blockly.Events.Move(this);
var event = new Blockly.Events.BlockMove(this);
this.xy_.translate(dx, dy);
event.recordNew();
Blockly.Events.fire(event);

View file

@ -234,7 +234,7 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) {
* @private
*/
Blockly.BlockDragger.prototype.fireMoveEvent_ = function() {
var event = new Blockly.Events.Move(this.draggingBlock_);
var event = new Blockly.Events.BlockMove(this.draggingBlock_);
event.oldCoordinate = this.startXY_;
event.recordNew();
Blockly.Events.fire(event);

View file

@ -379,7 +379,7 @@ Blockly.BlockSvg.prototype.moveBy = function(dx, dy) {
goog.asserts.assert(!this.parentBlock_, 'Block has parent.');
var eventsEnabled = Blockly.Events.isEnabled();
if (eventsEnabled) {
var event = new Blockly.Events.Move(this);
var event = new Blockly.Events.BlockMove(this);
}
var xy = this.getRelativeToSurfaceXY();
this.translate(xy.x + dx, xy.y + dy);

View file

@ -121,7 +121,7 @@ Blockly.Comment.prototype.createEditor_ = function() {
});
Blockly.bindEventWithChecks_(textarea, 'change', this, function(/* e */) {
if (this.text_ != textarea.value) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this.block_, 'comment', null, this.text_, textarea.value));
this.text_ = textarea.value;
}
@ -259,7 +259,7 @@ Blockly.Comment.prototype.getText = function() {
*/
Blockly.Comment.prototype.setText = function(text) {
if (this.text_ != text) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this.block_, 'comment', null, this.text_, text));
this.text_ = text;
}

View file

@ -218,7 +218,7 @@ Blockly.Connection.prototype.connect_ = function(childConnection) {
var event;
if (Blockly.Events.isEnabled()) {
event = new Blockly.Events.Move(childBlock);
event = new Blockly.Events.BlockMove(childBlock);
}
// Establish the connections.
Blockly.Connection.connectReciprocally_(parentConnection, childConnection);
@ -561,7 +561,7 @@ Blockly.Connection.prototype.disconnectInternal_ = function(parentBlock,
childBlock) {
var event;
if (Blockly.Events.isEnabled()) {
event = new Blockly.Events.Move(childBlock);
event = new Blockly.Events.BlockMove(childBlock);
}
var otherConnection = this.targetConnection;
otherConnection.targetConnection = null;

View file

@ -184,7 +184,7 @@ Blockly.ContextMenu.callbackFactory = function(block, xml) {
Blockly.Events.enable();
}
if (Blockly.Events.isEnabled() && !newBlock.isShadow()) {
Blockly.Events.fire(new Blockly.Events.Create(newBlock));
Blockly.Events.fire(new Blockly.Events.BlockCreate(newBlock));
}
newBlock.select();
};

View file

@ -55,29 +55,71 @@ Blockly.Events.recordUndo = true;
Blockly.Events.disabled_ = 0;
/**
* Name of event that creates a block.
* Name of event that creates a block. Will be deprecated for BLOCK_CREATE.
* @const
*/
Blockly.Events.CREATE = 'create';
/**
* Name of event that deletes a block.
* Name of event that creates a block.
* @const
*/
Blockly.Events.BLOCK_CREATE = Blockly.Events.CREATE;
/**
* Name of event that deletes a block. Will be deprecated for BLOCK_DELETE.
* @const
*/
Blockly.Events.DELETE = 'delete';
/**
* Name of event that changes a block.
* Name of event that deletes a block.
* @const
*/
Blockly.Events.BLOCK_DELETE = Blockly.Events.DELETE;
/**
* Name of event that changes a block. Will be deprecated for BLOCK_CHANGE.
* @const
*/
Blockly.Events.CHANGE = 'change';
/**
* Name of event that moves a block.
* Name of event that changes a block.
* @const
*/
Blockly.Events.BLOCK_CHANGE = Blockly.Events.CHANGE;
/**
* Name of event that moves a block. Will be deprecated for BLOCK_MOVE.
* @const
*/
Blockly.Events.MOVE = 'move';
/**
* Name of event that moves a block.
* @const
*/
Blockly.Events.BLOCK_MOVE = Blockly.Events.MOVE;
/**
* Name of event that creates a variable.
* @const
*/
Blockly.Events.VAR_CREATE = 'var_create';
/**
* Name of event that deletes a variable.
* @const
*/
Blockly.Events.VAR_DELETE = 'var_delete';
/**
* Name of event that renames a variable.
* @const
*/
Blockly.Events.VAR_RENAME = 'var_rename';
/**
* Name of event that records a UI change.
* @const
@ -276,6 +318,15 @@ Blockly.Events.fromJson = function(json, workspace) {
case Blockly.Events.MOVE:
event = new Blockly.Events.Move(null);
break;
case Blockly.Events.VAR_CREATE:
event = new Blockly.Events.VarCreate(null);
break;
case Blockly.Events.VAR_DELETE:
event = new Blockly.Events.VarDelete(null);
break;
case Blockly.Events.VAR_RENAME:
event = new Blockly.Events.VarRename(null);
break;
case Blockly.Events.UI:
event = new Blockly.Events.Ui(null);
break;
@ -289,13 +340,17 @@ Blockly.Events.fromJson = function(json, workspace) {
/**
* Abstract class for an event.
* @param {Blockly.Block} block The block.
* @param {Blockly.Block|Blockly.VariableModel} elem The block or variable.
* @constructor
*/
Blockly.Events.Abstract = function(block) {
if (block) {
this.blockId = block.id;
this.workspaceId = block.workspace.id;
Blockly.Events.Abstract = function(elem) {
if (elem instanceof Blockly.Block) {
this.blockId = elem.id;
this.workspaceId = elem.workspace.id;
}
else if (elem instanceof Blockly.VariableModel){
this.workspaceId = elem.workspace.id;
this.varId = elem.getId();
}
this.group = Blockly.Events.group_;
this.recordUndo = Blockly.Events.recordUndo;
@ -312,6 +367,9 @@ Blockly.Events.Abstract.prototype.toJson = function() {
if (this.blockId) {
json['blockId'] = this.blockId;
}
if (this.varId) {
json['varId'] = this.varId;
}
if (this.group) {
json['group'] = this.group;
}
@ -324,6 +382,7 @@ Blockly.Events.Abstract.prototype.toJson = function() {
*/
Blockly.Events.Abstract.prototype.fromJson = function(json) {
this.blockId = json['blockId'];
this.varId = json['varId'];
this.group = json['group'];
};
@ -344,6 +403,21 @@ Blockly.Events.Abstract.prototype.run = function(/*forward*/) {
// Defined by subclasses.
};
/**
* Get workspace the event belongs to.
* @return {Blockly.Workspace} The workspace the event belongs to.
* @throws {Error} if workspace is null.
* @private
*/
Blockly.Events.Abstract.prototype.getEventWorkspace_ = function() {
var workspace = Blockly.Workspace.getById(this.workspaceId);
if (!workspace) {
throw Error('Workspace is null. Event must have been generated from real' +
' Blockly events.');
}
return workspace;
};
/**
* Class for a block creation event.
* @param {Blockly.Block} block The created block. Null for a blank event.
@ -365,6 +439,14 @@ Blockly.Events.Create = function(block) {
};
goog.inherits(Blockly.Events.Create, Blockly.Events.Abstract);
/**
* Class for a block creation event.
* @param {Blockly.Block} block The created block. Null for a blank event.
* @extends {Blockly.Events.Abstract}
* @constructor
*/
Blockly.Events.BlockCreate = Blockly.Events.Create;
/**
* Type of this event.
* @type {string}
@ -397,7 +479,7 @@ Blockly.Events.Create.prototype.fromJson = function(json) {
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.Create.prototype.run = function(forward) {
var workspace = Blockly.Workspace.getById(this.workspaceId);
var workspace = this.getEventWorkspace_();
if (forward) {
var xml = goog.dom.createDom('xml');
xml.appendChild(this.xml);
@ -439,6 +521,14 @@ Blockly.Events.Delete = function(block) {
};
goog.inherits(Blockly.Events.Delete, Blockly.Events.Abstract);
/**
* Class for a block deletion event.
* @param {Blockly.Block} block The deleted block. Null for a blank event.
* @extends {Blockly.Events.Abstract}
* @constructor
*/
Blockly.Events.BlockDelete = Blockly.Events.Delete;
/**
* Type of this event.
* @type {string}
@ -469,7 +559,7 @@ Blockly.Events.Delete.prototype.fromJson = function(json) {
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.Delete.prototype.run = function(forward) {
var workspace = Blockly.Workspace.getById(this.workspaceId);
var workspace = this.getEventWorkspace_();
if (forward) {
for (var i = 0, id; id = this.ids[i]; i++) {
var block = workspace.getBlockById(id);
@ -509,6 +599,18 @@ Blockly.Events.Change = function(block, element, name, oldValue, newValue) {
};
goog.inherits(Blockly.Events.Change, Blockly.Events.Abstract);
/**
* Class for a block change event.
* @param {Blockly.Block} block The changed block. Null for a blank event.
* @param {string} element One of 'field', 'comment', 'disabled', etc.
* @param {?string} name Name of input or field affected, or null.
* @param {string} oldValue Previous value of element.
* @param {string} newValue New value of element.
* @extends {Blockly.Events.Abstract}
* @constructor
*/
Blockly.Events.BlockChange = Blockly.Events.Change;
/**
* Type of this event.
* @type {string}
@ -553,7 +655,7 @@ Blockly.Events.Change.prototype.isNull = function() {
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.Change.prototype.run = function(forward) {
var workspace = Blockly.Workspace.getById(this.workspaceId);
var workspace = this.getEventWorkspace_();
var block = workspace.getBlockById(this.blockId);
if (!block) {
console.warn("Can't change non-existant block: " + this.blockId);
@ -625,6 +727,15 @@ Blockly.Events.Move = function(block) {
};
goog.inherits(Blockly.Events.Move, Blockly.Events.Abstract);
/**
* Class for a block move event. Created before the move.
* @param {Blockly.Block} block The moved block. Null for a blank event.
* @extends {Blockly.Events.Abstract}
* @constructor
*/
Blockly.Events.BlockMove = Blockly.Events.Move;
/**
* Type of this event.
* @type {string}
@ -713,7 +824,7 @@ Blockly.Events.Move.prototype.isNull = function() {
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.Move.prototype.run = function(forward) {
var workspace = Blockly.Workspace.getById(this.workspaceId);
var workspace = this.getEventWorkspace_();
var block = workspace.getBlockById(this.blockId);
if (!block) {
console.warn("Can't move non-existant block: " + this.blockId);
@ -802,6 +913,178 @@ Blockly.Events.Ui.prototype.fromJson = function(json) {
this.newValue = json['newValue'];
};
/**
* Class for a variable creation event.
* @param {Blockly.VariableModel} variable The created variable.
* Null for a blank event.
* @extends {Blockly.Events.Abstract}
* @constructor
*/
Blockly.Events.VarCreate = function(variable) {
if (!variable) {
return; // Blank event to be populated by fromJson.
}
Blockly.Events.VarCreate.superClass_.constructor.call(this, variable);
this.varType = variable.type;
this.varName = variable.name;
};
goog.inherits(Blockly.Events.VarCreate, Blockly.Events.Abstract);
/**
* Type of this event.
* @type {string}
*/
Blockly.Events.VarCreate.prototype.type = Blockly.Events.VAR_CREATE;
/**
* Encode the event as JSON.
* @return {!Object} JSON representation.
*/
Blockly.Events.VarCreate.prototype.toJson = function() {
var json = Blockly.Events.VarCreate.superClass_.toJson.call(this);
json['varType'] = this.varType;
json['varName'] = this.varName;
return json;
};
/**
* Decode the JSON event.
* @param {!Object} json JSON representation.
*/
Blockly.Events.VarCreate.prototype.fromJson = function(json) {
Blockly.Events.VarCreate.superClass_.fromJson.call(this, json);
this.varType = json['varType'];
this.varName = json['varName'];
};
/**
* Run a variable creation event.
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.VarCreate.prototype.run = function(forward) {
var workspace = this.getEventWorkspace_();
if (forward) {
workspace.createVariable(this.varName, this.varType, this.varId);
} else {
workspace.deleteVariableById(this.varId);
}
};
/**
* Class for a variable deletion event.
* @param {Blockly.VariableModel} variable The deleted variable.
* Null for a blank event.
* @extends {Blockly.Events.Abstract}
* @constructor
*/
Blockly.Events.VarDelete = function(variable) {
if (!variable) {
return; // Blank event to be populated by fromJson.
}
Blockly.Events.VarDelete.superClass_.constructor.call(this, variable);
this.varType = variable.type;
this.varName = variable.name;
};
goog.inherits(Blockly.Events.VarDelete, Blockly.Events.Abstract);
/**
* Type of this event.
* @type {string}
*/
Blockly.Events.VarDelete.prototype.type = Blockly.Events.VAR_DELETE;
/**
* Encode the event as JSON.
* @return {!Object} JSON representation.
*/
Blockly.Events.VarDelete.prototype.toJson = function() {
var json = Blockly.Events.VarDelete.superClass_.toJson.call(this);
json['varType'] = this.varType;
json['varName'] = this.varName;
return json;
};
/**
* Decode the JSON event.
* @param {!Object} json JSON representation.
*/
Blockly.Events.VarDelete.prototype.fromJson = function(json) {
Blockly.Events.VarDelete.superClass_.fromJson.call(this, json);
this.varType = json['varType'];
this.varName = json['varName'];
};
/**
* Run a variable deletion event.
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.VarDelete.prototype.run = function(forward) {
var workspace = this.getEventWorkspace_();
if (forward) {
workspace.deleteVariableById(this.varId);
} else {
workspace.createVariable(this.varName, this.varType, this.varId);
}
};
/**
* Class for a variable rename event.
* @param {Blockly.VariableModel} variable The renamed variable.
* Null for a blank event.
* @param {string} newName The new name the variable will be changed to.
* @extends {Blockly.Events.Abstract}
* @constructor
*/
Blockly.Events.VarRename = function(variable, newName) {
if (!variable) {
return; // Blank event to be populated by fromJson.
}
Blockly.Events.VarRename.superClass_.constructor.call(this, variable);
this.oldName = variable.name;
this.newName = newName;
};
goog.inherits(Blockly.Events.VarRename, Blockly.Events.Abstract);
/**
* Type of this event.
* @type {string}
*/
Blockly.Events.VarRename.prototype.type = Blockly.Events.VAR_RENAME;
/**
* Encode the event as JSON.
* @return {!Object} JSON representation.
*/
Blockly.Events.VarRename.prototype.toJson = function() {
var json = Blockly.Events.VarRename.superClass_.toJson.call(this);
json['oldName'] = this.oldName;
json['newName'] = this.newName;
return json;
};
/**
* Decode the JSON event.
* @param {!Object} json JSON representation.
*/
Blockly.Events.VarRename.prototype.fromJson = function(json) {
Blockly.Events.VarRename.superClass_.fromJson.call(this, json);
this.oldName = json['oldName'];
this.newName = json['newName'];
};
/**
* Run a variable rename event.
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.VarRename.prototype.run = function(forward) {
var workspace = this.getEventWorkspace_();
if (forward) {
workspace.renameVariableById(this.varId, this.newName);
} else {
workspace.renameVariableById(this.varId, this.oldName);
}
};
/**
* Enable/disable a block depending on whether it is properly connected.
* Use this on applications where all blocks should be connected to a top block.

View file

@ -399,8 +399,6 @@ Blockly.Field.prototype.render_ = function() {
**/
Blockly.Field.prototype.updateWidth = function() {
var width = Blockly.Field.getCachedWidth(this.textElement_);
// Calculate width of field
width = Blockly.Field.getCachedWidth(this.textElement_);
// Add padding to left and right of text.
if (this.EDITABLE) {
@ -623,7 +621,7 @@ Blockly.Field.prototype.setValue = function(newValue) {
return;
}
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this.sourceBlock_, 'field', this.name, oldValue, newValue));
}
this.setText(newValue);

View file

@ -94,7 +94,7 @@ Blockly.FieldCheckbox.prototype.setValue = function(newBool) {
(newBool.toUpperCase() == 'TRUE') : !!newBool;
if (this.state_ !== newState) {
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this.sourceBlock_, 'field', this.name, this.state_, newState));
}
this.state_ = newState;

View file

@ -101,7 +101,7 @@ Blockly.FieldColour.prototype.getValue = function() {
Blockly.FieldColour.prototype.setValue = function(colour) {
if (this.sourceBlock_ && Blockly.Events.isEnabled() &&
this.colour_ != colour) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this.sourceBlock_, 'field', this.name, this.colour_, colour));
}
this.colour_ = colour;

View file

@ -388,7 +388,7 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) {
return; // No change if null.
}
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this.sourceBlock_, 'field', this.name, this.value_, newValue));
}
// Clear menu item for old value.

View file

@ -144,7 +144,7 @@ Blockly.FieldTextInput.prototype.setText = function(newText) {
return;
}
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this.sourceBlock_, 'field', this.name, this.text_, newText));
}
Blockly.Field.prototype.setText.call(this, newText);

View file

@ -107,9 +107,24 @@ Blockly.FieldVariable.prototype.getValue = function() {
*/
Blockly.FieldVariable.prototype.setValue = function(newValue) {
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
this.sourceBlock_, 'field', this.name, this.value_, newValue));
}
if (this.sourceBlock_) {
var variable = this.sourceBlock_.workspace.getVariableById(newValue);
if (variable) {
this.setText(variable.name);
this.value_ = newValue;
return;
}
// TODO(marisaleung): Remove name lookup after converting all Field Variable
// instances to use id instead of name.
else if (variable = this.sourceBlock_.workspace.getVariable(newValue)) {
this.setText(newValue);
this.value_ = variable.getId();
return;
}
}
this.value_ = newValue;
this.setText(newValue);
};

View file

@ -19,9 +19,7 @@
*/
/**
* @fileoverview Base class for a file tray containing blocks that may be
* dragged into the workspace. Defines basic interactions that are shared
* between vertical and horizontal flyouts.
* @fileoverview Flyout tray containing blocks which may be created.
* @author fraser@google.com (Neil Fraser)
*/
'use strict';
@ -278,6 +276,13 @@ Blockly.Flyout.prototype.init = function(targetWorkspace) {
// A flyout connected to a workspace doesn't have its own current gesture.
this.workspace_.getGesture =
this.targetWorkspace_.getGesture.bind(this.targetWorkspace_);
// Get variables from the main workspace rather than the target workspace.
this.workspace_.getVariable =
this.targetWorkspace_.getVariable.bind(this.targetWorkspace_);
this.workspace_.getVariableById =
this.targetWorkspace_.getVariableById.bind(this.targetWorkspace_);
};
/**
@ -529,7 +534,7 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() {
/**
* Add listeners to a block that has been added to the flyout.
* @param {Element} root The root node of the SVG group the block is in.
* @param {!Element} root The root node of the SVG group the block is in.
* @param {!Blockly.Block} block The block to add listeners for.
* @param {!Element} rect The invisible rectangle under the block that acts as
* a button for that block.
@ -631,7 +636,6 @@ Blockly.Flyout.prototype.reflow = function() {
this.workspace_.removeChangeListener(this.reflowWrapper_);
}
var blocks = this.workspace_.getTopBlocks(false);
this.reflowInternal_(blocks);
if (this.reflowWrapper_) {
this.workspace_.addChangeListener(this.reflowWrapper_);

View file

@ -325,7 +325,7 @@ Blockly.Mutator.prototype.workspaceChanged_ = function() {
var newMutationDom = block.mutationToDom();
var newMutation = newMutationDom && Blockly.Xml.domToText(newMutationDom);
if (oldMutation != newMutation) {
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
block, 'mutation', null, oldMutation, newMutation));
// Ensure that any bump is part of this mutation's event group.
var group = Blockly.Events.getGroup();

View file

@ -278,7 +278,7 @@ Blockly.Procedures.mutateCallers = function(defBlock) {
// undo action since it is deterministically tied to the procedure's
// definition mutation.
Blockly.Events.recordUndo = false;
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new Blockly.Events.BlockChange(
caller, 'mutation', null, oldMutation, newMutation));
Blockly.Events.recordUndo = oldRecordUndo;
}

View file

@ -32,10 +32,11 @@ goog.require('Blockly.VariableModel');
* Class for a variable map. This contains a dictionary data structure with
* variable types as keys and lists of variables as values. The list of
* variables are the type indicated by the key.
* @param {!Blockly.Workspace} workspace The workspace this map belongs to.
* @constructor
*/
Blockly.VariableMap = function() {
/**
Blockly.VariableMap = function(workspace) {
/**
* @type {!Object<string, !Array.<Blockly.VariableModel>>}
* A map from variable type to list of variable names. The lists contain all
* of the named variables in the workspace, including variables
@ -43,6 +44,12 @@ Blockly.VariableMap = function() {
* @private
*/
this.variableMap_ = {};
/**
* The workspace this map belongs to.
* @type {!Blockly.Workspace}
*/
this.workspace = workspace;
};
/**
@ -54,7 +61,6 @@ Blockly.VariableMap.prototype.clear = function() {
/**
* Rename the given variable by updating its name in the variable map.
* TODO: #468
* @param {?Blockly.VariableModel} variable Variable to rename.
* @param {string} newName New variable name.
*/
@ -81,11 +87,19 @@ Blockly.VariableMap.prototype.renameVariable = function(variable, newName) {
} else if (variableIndex == newVariableIndex ||
variableIndex != -1 && newVariableIndex == -1) {
// Only changing case, or renaming to a completely novel name.
this.variableMap_[type][variableIndex].name = newName;
var variableToRename = this.variableMap_[type][variableIndex];
Blockly.Events.fire(new Blockly.Events.VarRename(variableToRename,
newName));
variableToRename.name = newName;
} else if (variableIndex != -1 && newVariableIndex != -1) {
// Renaming one existing variable to another existing variable.
// The case might have changed, so we update the destination ID.
this.variableMap_[type][newVariableIndex].name = newName;
var variableToRename = this.variableMap_[type][newVariableIndex];
Blockly.Events.fire(new Blockly.Events.VarRename(variableToRename,
newName));
var variableToDelete = this.variableMap_[type][variableIndex];
Blockly.Events.fire(new Blockly.Events.VarDelete(variableToDelete));
variableToRename.name = newName;
this.variableMap_[type].splice(variableIndex, 1);
}
};
@ -123,7 +137,7 @@ Blockly.VariableMap.prototype.createVariable = function(name, opt_type, opt_id)
opt_id = opt_id || Blockly.utils.genUid();
opt_type = opt_type || '';
variable = new Blockly.VariableModel(name, opt_type, opt_id);
variable = new Blockly.VariableModel(this.workspace, name, opt_type, opt_id);
// If opt_type is not a key, create a new list.
if (!this.variableMap_[opt_type]) {
this.variableMap_[opt_type] = [variable];
@ -143,6 +157,7 @@ Blockly.VariableMap.prototype.deleteVariable = function(variable) {
for (var i = 0, tempVar; tempVar = variableList[i]; i++) {
if (tempVar.getId() == variable.getId()) {
variableList.splice(i, 1);
Blockly.Events.fire(new Blockly.Events.VarDelete(variable));
return;
}
}

View file

@ -32,6 +32,7 @@ goog.require('goog.string');
/**
* Class for a variable model.
* Holds information for the variable including name, id, and type.
* @param {!Blockly.Workspace} workspace The variable's workspace.
* @param {!string} name The name of the variable. This must be unique across
* variables and procedures.
* @param {?string} opt_type The type of the variable like 'int' or 'string'.
@ -42,7 +43,13 @@ goog.require('goog.string');
* @see {Blockly.FieldVariable}
* @constructor
*/
Blockly.VariableModel = function(name, opt_type, opt_id) {
Blockly.VariableModel = function(workspace, name, opt_type, opt_id) {
/**
* The workspace the variable is in.
* @type {!Blockly.Workspace}
*/
this.workspace = workspace;
/**
* The name of the variable, typically defined by the user. It must be
* unique across all names used for procedures and variables. It may be
@ -68,6 +75,8 @@ Blockly.VariableModel = function(name, opt_type, opt_id) {
* @private
*/
this.id_ = opt_id || Blockly.utils.genUid();
Blockly.Events.fire(new Blockly.Events.VarCreate(this));
};
/**

View file

@ -89,7 +89,7 @@ Blockly.Workspace = function(opt_options) {
* that are not currently in use.
* @private
*/
this.variableMap_ = new Blockly.VariableMap();
this.variableMap_ = new Blockly.VariableMap(this);
};
/**
@ -251,7 +251,6 @@ Blockly.Workspace.prototype.updateVariableStore = function(clear) {
/**
* Rename a variable by updating its name in the variable map. Identify the
* variable to rename with the given variable.
* TODO: #468
* @param {?Blockly.VariableModel} variable Variable to rename.
* @param {string} newName New variable name.
*/
@ -280,16 +279,14 @@ Blockly.Workspace.prototype.renameVariableInternal_ = function(variable, newName
blocks[i].renameVar(oldCase, newName);
}
}
Blockly.Events.setGroup(false);
this.variableMap_.renameVariable(variable, newName);
Blockly.Events.setGroup(false);
};
/**
* Rename a variable by updating its name in the variable map. Identify the
* variable to rename with the given name.
* TODO: #468
* @param {string} oldName Variable to rename.
* @param {string} newName New variable name.
*/
@ -299,6 +296,7 @@ Blockly.Workspace.prototype.renameVariable = function(oldName, newName) {
this.renameVariableInternal_(variable, newName);
};
/**
* Rename a variable by updating its name in the variable map. Identify the
* variable to rename with the given id.
@ -343,7 +341,7 @@ Blockly.Workspace.prototype.getVariableUses = function(name) {
for (var j = 0; j < blockVariables.length; j++) {
var varName = blockVariables[j];
// Variable name may be null if the block is only half-built.
if (varName && Blockly.Names.equals(varName, name)) {
if (varName && name && Blockly.Names.equals(varName, name)) {
uses.push(blocks[i]);
}
}
@ -399,6 +397,8 @@ Blockly.Workspace.prototype.deleteVariableById = function(id) {
var variable = this.getVariableById(id);
if (variable) {
this.deleteVariableInternal_(variable);
} else {
console.warn("Can't delete non-existant variable: " + id);
}
};
@ -414,9 +414,8 @@ Blockly.Workspace.prototype.deleteVariableInternal_ = function(variable) {
for (var i = 0; i < uses.length; i++) {
uses[i].dispose(true, false);
}
Blockly.Events.setGroup(false);
this.variableMap_.deleteVariable(variable);
Blockly.Events.setGroup(false);
};
/**
@ -498,10 +497,14 @@ Blockly.Workspace.prototype.undo = function(redo) {
}
events = Blockly.Events.filter(events, redo);
Blockly.Events.recordUndo = false;
for (var i = 0, event; event = events[i]; i++) {
event.run(redo);
try {
for (var i = 0, event; event = events[i]; i++) {
event.run(redo);
}
}
finally {
Blockly.Events.recordUndo = true;
}
Blockly.Events.recordUndo = true;
};
/**

View file

@ -972,7 +972,7 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) {
Blockly.Events.enable();
}
if (Blockly.Events.isEnabled() && !block.isShadow()) {
Blockly.Events.fire(new Blockly.Events.Create(block));
Blockly.Events.fire(new Blockly.Events.BlockCreate(block));
}
block.select();
};
@ -1036,7 +1036,6 @@ Blockly.WorkspaceSvg.prototype.deleteVariableById = function(id) {
/**
* Create a new variable with the given name. Update the flyout to show the new
* variable immediately.
* TODO: #468
* @param {string} name The new variable's name.
* @param {string=} opt_type The type of the variable like 'int' or 'string'.
* Does not need to be unique. Field_variable can filter variables based on

View file

@ -333,38 +333,46 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) {
if (workspace.setResizesEnabled) {
workspace.setResizesEnabled(false);
}
for (var i = 0; i < childCount; i++) {
var xmlChild = xml.childNodes[i];
var name = xmlChild.nodeName.toLowerCase();
if (name == 'block' ||
(name == 'shadow' && !Blockly.Events.recordUndo)) {
// Allow top-level shadow blocks if recordUndo is disabled since
// that means an undo is in progress. Such a block is expected
// to be moved to a nested destination in the next operation.
var block = Blockly.Xml.domToBlock(xmlChild, workspace);
newBlockIds.push(block.id);
var blockX = parseInt(xmlChild.getAttribute('x'), 10);
var blockY = parseInt(xmlChild.getAttribute('y'), 10);
if (!isNaN(blockX) && !isNaN(blockY)) {
block.moveBy(workspace.RTL ? width - blockX : blockX, blockY);
}
} else if (name == 'shadow') {
goog.asserts.fail('Shadow block cannot be a top-level block.');
} else if (name == 'variables') {
if (i == 1) {
Blockly.Xml.domToVariables(xmlChild, workspace);
}
else {
throw Error('\'variables\' tag must be the first element in the' +
'workspace XML, but it was found in another location.');
var variablesFirst = true;
try {
for (var i = 0; i < childCount; i++) {
var xmlChild = xml.childNodes[i];
var name = xmlChild.nodeName.toLowerCase();
if (name == 'block' ||
(name == 'shadow' && !Blockly.Events.recordUndo)) {
// Allow top-level shadow blocks if recordUndo is disabled since
// that means an undo is in progress. Such a block is expected
// to be moved to a nested destination in the next operation.
var block = Blockly.Xml.domToBlock(xmlChild, workspace);
newBlockIds.push(block.id);
var blockX = parseInt(xmlChild.getAttribute('x'), 10);
var blockY = parseInt(xmlChild.getAttribute('y'), 10);
if (!isNaN(blockX) && !isNaN(blockY)) {
block.moveBy(workspace.RTL ? width - blockX : blockX, blockY);
}
variablesFirst = false;
} else if (name == 'shadow') {
goog.asserts.fail('Shadow block cannot be a top-level block.');
variablesFirst = false;
} else if (name == 'variables') {
if (variablesFirst) {
Blockly.Xml.domToVariables(xmlChild, workspace);
}
else {
throw Error('\'variables\' tag must exist once before block and ' +
'shadow tag elements in the workspace XML, but it was found in ' +
'another location.');
}
variablesFirst = false;
}
}
}
if (!existingGroup) {
Blockly.Events.setGroup(false);
finally {
if (!existingGroup) {
Blockly.Events.setGroup(false);
}
Blockly.Field.stopCache();
}
Blockly.Field.stopCache();
workspace.updateVariableStore(false);
// Re-enable workspace resizing.
if (workspace.setResizesEnabled) {
@ -491,7 +499,7 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) {
Blockly.Events.enable();
}
if (Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.Create(topBlock));
Blockly.Events.fire(new Blockly.Events.BlockCreate(topBlock));
}
return topBlock;
};
@ -701,6 +709,9 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
goog.asserts.assert(child.isShadow(),
'Shadow block not allowed non-shadow child.');
}
// Ensure this block doesn't have any variable inputs.
goog.asserts.assert(block.getVars().length == 0,
'Shadow blocks cannot have variable fields.');
block.setShadow(true);
}
return block;

View file

@ -1,7 +1,7 @@
{
"@metadata": {
"author": "Ellen Spertus <ellen.spertus@gmail.com>",
"lastupdated": "2017-05-25 07:58:37.810709",
"lastupdated": "2017-06-22 11:21:38.108160",
"locale": "en",
"messagedocumentation" : "qqq"
},

394
tests/jsunit/event_test.js Normal file
View file

@ -0,0 +1,394 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2017 Google Inc.
* https://developers.google.com/blockly/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Tests for Blockly.Events
* @author marisaleung@google.com (Marisa Leung)
*/
'use strict';
goog.require('goog.testing');
goog.require('goog.testing.MockControl');
var mockControl_;
var workspace;
function eventTest_setUp() {
workspace = new Blockly.Workspace();
mockControl_ = new goog.testing.MockControl();
}
function eventTest_setUpWithMockBlocks() {
eventTest_setUp();
Blockly.defineBlocksWithJsonArray([{
'type': 'field_variable_test_block',
'message0': '%1',
'args0': [
{
'type': 'field_variable',
'name': 'VAR',
'variable': 'item'
}
],
}]);
}
function eventTest_tearDown() {
mockControl_.$tearDown();
workspace.dispose();
}
function eventTest_tearDownWithMockBlocks() {
eventTest_tearDown();
delete Blockly.Blocks.field_variable_test_block;
}
function test_abstract_constructor_block() {
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, '1');
var block = new Blockly.Block(workspace, 'field_variable_test_block');
var event = new Blockly.Events.Abstract(block);
assertUndefined(event.varId);
checkExactEventValues(event, {'blockId': '1', 'workspaceId': workspace.id,
'group': '', 'recordUndo': true});
eventTest_tearDownWithMockBlocks();
}
function test_abstract_constructor_variable() {
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, '1');
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.Abstract(variable);
assertUndefined(event.blockId);
checkExactEventValues(event, {'varId': 'id1',
'workspaceId': workspace.id, 'group': '', 'recordUndo': true});
eventTest_tearDownWithMockBlocks();
}
function test_abstract_constructor_null() {
eventTest_setUpWithMockBlocks();
var event = new Blockly.Events.Abstract(null);
assertUndefined(event.blockId);
assertUndefined(event.workspaceId);
checkExactEventValues(event, {'group': '', 'recordUndo': true});
eventTest_tearDownWithMockBlocks();
}
function checkCreateEventValues(event, block, ids, type) {
var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block));
var result_xml = Blockly.Xml.domToText(event.xml);
assertEquals(expected_xml, result_xml);
isEqualArrays(ids, event.ids);
assertEquals(type, event.type);
}
function checkDeleteEventValues(event, block, ids, type) {
var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block));
var result_xml = Blockly.Xml.domToText(event.oldXml);
assertEquals(expected_xml, result_xml);
isEqualArrays(ids, event.ids);
assertEquals(type, event.type);
}
function checkExactEventValues(event, values) {
var keys = Object.keys(values);
for (var i = 0, field; field = keys[i]; i++) {
assertEquals(values[field], event[field]);
}
}
function test_create_constructor() {
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
var block = new Blockly.Block(workspace, 'field_variable_test_block');
var event = new Blockly.Events.Create(block);
checkCreateEventValues(event, block, ['1'], 'create');
eventTest_tearDownWithMockBlocks();
}
function test_blockCreate_constructor() {
// expect that blockCreate behaves the same as create.
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
var block = new Blockly.Block(workspace, 'field_variable_test_block');
var event = new Blockly.Events.BlockCreate(block);
checkCreateEventValues(event, block, ['1'], 'create');
eventTest_tearDownWithMockBlocks();
}
function test_delete_constructor() {
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
var block = new Blockly.Block(workspace, 'field_variable_test_block');
var event = new Blockly.Events.Delete(block);
checkDeleteEventValues(event, block, ['1'], 'delete');
eventTest_tearDownWithMockBlocks();
}
function test_blockDelete_constructor() {
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
var block = new Blockly.Block(workspace, 'field_variable_test_block');
var event = new Blockly.Events.BlockDelete(block);
checkDeleteEventValues(event, block, ['1'], 'delete');
eventTest_tearDownWithMockBlocks();
}
function test_change_constructor() {
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
var block = new Blockly.Block(workspace, 'field_variable_test_block');
var event = new Blockly.Events.Change(block, 'field', 'VAR', 'item', 'item2');
checkExactEventValues(event, {'element': 'field', 'name': 'VAR',
'oldValue': 'item', 'newValue': 'item2', 'type': 'change'});
eventTest_tearDownWithMockBlocks();
}
function test_blockChange_constructor() {
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
var block = new Blockly.Block(workspace, 'field_variable_test_block');
var event = new Blockly.Events.BlockChange(block, 'field', 'VAR', 'item',
'item2');
checkExactEventValues(event, {'element': 'field', 'name': 'VAR',
'oldValue': 'item', 'newValue': 'item2', 'type': 'change'});
eventTest_tearDownWithMockBlocks();
}
function test_move_constructorCoordinate() {
// Expect the oldCoordinate to be set.
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']);
var block1 = new Blockly.Block(workspace, 'field_variable_test_block');
var coordinate = new goog.math.Coordinate(3,4);
block1.xy_ = coordinate;
var event = new Blockly.Events.Move(block1);
checkExactEventValues(event, {'oldCoordinate': coordinate,
'type': 'move'});
eventTest_tearDownWithMockBlocks();
}
function test_move_constructoroldParentId() {
// Expect the oldParentId to be set but not the oldCoordinate to be set.
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']);
var block1 = new Blockly.Block(workspace, 'field_variable_test_block');
var block2 = new Blockly.Block(workspace, 'field_variable_test_block');
block1.parentBlock_ = block2;
block1.xy_ = new goog.math.Coordinate(3,4);
var event = new Blockly.Events.Move(block1);
checkExactEventValues(event, {'oldCoordinate': undefined,
'oldParentId': '2', 'type': 'move'});
block1.parentBlock_ = null;
eventTest_tearDownWithMockBlocks();
}
function test_blockMove_constructorCoordinate() {
// Expect the oldCoordinate to be set.
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']);
var block1 = new Blockly.Block(workspace, 'field_variable_test_block');
var coordinate = new goog.math.Coordinate(3,4);
block1.xy_ = coordinate;
var event = new Blockly.Events.BlockMove(block1);
checkExactEventValues(event, {'oldCoordinate': coordinate,
'type': 'move'});
eventTest_tearDownWithMockBlocks();
}
function test_blockMove_constructoroldParentId() {
// Expect the oldParentId to be set but not the oldCoordinate to be set.
eventTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']);
var block1 = new Blockly.Block(workspace, 'field_variable_test_block');
var block2 = new Blockly.Block(workspace, 'field_variable_test_block');
block1.parentBlock_ = block2;
block1.xy_ = new goog.math.Coordinate(3,4);
var event = new Blockly.Events.BlockMove(block1);
checkExactEventValues(event, {'oldCoordinate': undefined,
'oldParentId': '2', 'type': 'move'});
block1.parentBlock_ = null;
eventTest_tearDownWithMockBlocks();
}
function test_varCreate_constructor() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarCreate(variable);
checkExactEventValues(event, {'varName': 'name1', 'varType': 'type1',
'type': 'var_create'});
eventTest_tearDown();
}
function test_varCreate_toJson() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarCreate(variable);
var json = event.toJson();
var expectedJson = ({type: "var_create", varId: "id1", varType: "type1",
varName: "name1"});
assertEquals(JSON.stringify(expectedJson), JSON.stringify(json));
eventTest_tearDown();
}
function test_varCreate_fromJson() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarCreate(variable);
var event2 = new Blockly.Events.VarCreate(null);
var json = event.toJson();
event2.fromJson(json);
assertEquals(JSON.stringify(json), JSON.stringify(event2.toJson()));
eventTest_tearDown();
}
function test_varCreate_runForward() {
eventTest_setUp();
var json = {type: "var_create", varId: "id1", varType: "type1",
varName: "name1"};
var event = Blockly.Events.fromJson(json, workspace);
assertNull(workspace.getVariableById('id1'));
event.run(true);
checkVariableValues(workspace, 'name1', 'type1', 'id1');
eventTest_tearDown();
}
function test_varCreate_runBackwards() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarCreate(variable);
assertNotNull(workspace.getVariableById('id1'));
event.run(false);
assertNull(workspace.getVariableById('id1'));
eventTest_tearDown();
}
function test_varDelete_constructor() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarDelete(variable);
checkExactEventValues(event, {'varName': 'name1', 'varType': 'type1',
'varId':'id1', 'type': 'var_delete'});
eventTest_tearDown();
}
function test_varDelete_toJson() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarDelete(variable);
var json = event.toJson();
var expectedJson = ({type: "var_delete", varId: "id1", varType: "type1",
varName: "name1"});
assertEquals(JSON.stringify(expectedJson), JSON.stringify(json));
eventTest_tearDown();
}
function test_varDelete_fromJson() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarDelete(variable);
var event2 = new Blockly.Events.VarDelete(null);
var json = event.toJson();
event2.fromJson(json);
assertEquals(JSON.stringify(json), JSON.stringify(event2.toJson()));
eventTest_tearDown();
}
function test_varDelete_runForwards() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarDelete(variable);
assertNotNull(workspace.getVariableById('id1'));
event.run(true);
assertNull(workspace.getVariableById('id1'));
eventTest_tearDown();
}
function test_varDelete_runBackwards() {
eventTest_setUp();
var json = {type: "var_delete", varId: "id1", varType: "type1",
varName: "name1"};
var event = Blockly.Events.fromJson(json, workspace);
assertNull(workspace.getVariableById('id1'));
event.run(false);
checkVariableValues(workspace, 'name1', 'type1', 'id1');
eventTest_tearDown();
}
function test_varRename_constructor() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarRename(variable, 'name2');
checkExactEventValues(event, {'varId': 'id1', 'oldName': 'name1',
'newName': 'name2', 'type': 'var_rename'});
eventTest_tearDown();
}
function test_varRename_toJson() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarRename(variable, 'name2');
var json = event.toJson();
var expectedJson = ({type: "var_rename", varId: "id1", oldName: "name1",
newName: "name2"});
assertEquals(JSON.stringify(expectedJson), JSON.stringify(json));
eventTest_tearDown();
}
function test_varRename_fromJson() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarRename(variable, '');
var event2 = new Blockly.Events.VarRename(null);
var json = event.toJson();
event2.fromJson(json);
assertEquals(JSON.stringify(json), JSON.stringify(event2.toJson()));
eventTest_tearDown();
}
function test_varRename_runForward() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarRename(variable, 'name2');
event.run(true);
assertNull(workspace.getVariable('name1'));
checkVariableValues(workspace, 'name2', 'type1', 'id1');
eventTest_tearDown();
}
function test_varBackard_runForward() {
eventTest_setUp();
var variable = workspace.createVariable('name1', 'type1', 'id1');
var event = new Blockly.Events.VarRename(variable, 'name2');
event.run(false);
assertNull(workspace.getVariable('name2'));
checkVariableValues(workspace, 'name1', 'type1', 'id1');
eventTest_tearDown();
}

View file

@ -0,0 +1,79 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2017 Google Inc.
* https://developers.google.com/blockly/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Tests for Blockly.FieldVariable
* @author marisaleung@google.com (Marisa Leung)
*/
'use strict';
goog.require('goog.testing');
function fieldVariable_mockBlock(workspace) {
return {'workspace': workspace, 'isShadow': function(){return false;}};
}
function test_fieldVariable_Constructor() {
var workspace = new Blockly.Workspace();
var fieldVariable = new Blockly.FieldVariable('name1');
assertEquals('name1', fieldVariable.getText());
workspace.dispose();
}
function test_fieldVariable_setValueMatchId() {
// Expect the fieldVariable value to be set to variable name
var workspace = new Blockly.Workspace();
workspace.createVariable('name2', null, 'id1');
var fieldVariable = new Blockly.FieldVariable('name1');
var mockBlock = fieldVariable_mockBlock(workspace);
fieldVariable.setSourceBlock(mockBlock);
fieldVariable.setValue('id1');
assertEquals('name2', fieldVariable.getText());
assertEquals('id1', fieldVariable.value_);
workspace.dispose();
}
function test_fieldVariable_setValueMatchName() {
// Expect the fieldVariable value to be set to variable name
var workspace = new Blockly.Workspace();
workspace.createVariable('name2', null, 'id2');
var fieldVariable = new Blockly.FieldVariable('name1');
var mockBlock = fieldVariable_mockBlock(workspace);
fieldVariable.setSourceBlock(mockBlock);
fieldVariable.setValue('name2');
assertEquals('name2', fieldVariable.getText());
assertEquals('id2', fieldVariable.value_);
workspace.dispose();
}
function test_fieldVariable_setValueNoVariable() {
// Expect the fieldVariable value to be set to the passed in string. No error
// should be thrown.
var workspace = new Blockly.Workspace();
var fieldVariable = new Blockly.FieldVariable('name1');
var mockBlock = {'workspace': workspace,
'isShadow': function(){return false;}};
fieldVariable.setSourceBlock(mockBlock);
fieldVariable.setValue('id1');
assertEquals('id1', fieldVariable.getText());
assertEquals('id1', fieldVariable.value_);
workspace.dispose();
}

View file

@ -4,17 +4,21 @@
<meta charset="utf-8">
</head>
<body>
<script src="test_utilities.js"></script>
<script src="utils_test.js"></script>
<script src="connection_test.js"></script>
<script src="connection_db_test.js"></script>
<script src="extensions_test.js"></script>
<script src="event_test.js"></script>
<script src="field_test.js"></script>
<script src="field_angle_test.js"></script>
<script src="field_number_test.js"></script>
<script src="field_variable_test.js"></script>
<script src="generator_test.js"></script>
<script src="input_test.js"></script>
<script src="names_test.js"></script>
<script src="workspace_test.js"></script>
<script src="workspace_undo_redo_test.js"></script>
<script src="xml_test.js"></script>
<script src="json_test.js"></script>
<script src="variable_model_test.js"></script>

View file

@ -0,0 +1,91 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2017 Google Inc.
* https://developers.google.com/blockly/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Test utilities.
* @author marisaleung@google.com (Marisa Leung)
*/
'use strict';
goog.require('goog.testing');
/**
* Check that two arrays have the same content.
* @param {!Array.<string>} array1 The first array.
* @param {!Array.<string>} array2 The second array.
*/
function isEqualArrays(array1, array2) {
assertEquals(array1.length, array2.length);
for (var i = 0; i < array1.length; i++) {
assertEquals(array1[i], array2[i]);
}
}
/**
* Creates a controlled MethodMock. Sets the expected return values and
* the parameters if any exist. Sets the method to replay.
* @param {!goog.testing.MockControl} mockControl Object that holds a set
* of mocks for this test.
* @param {!Object} scope The scope of the method to be mocked out.
* @param {!string} funcName The name of the function we're going to mock.
* @param {Array<Object>} parameters The parameters to call the mock with.
* @param {Array<!Object>} return_values The values to return when called.
* @return {!goog.testing.MockInterface} The mocked method.
*/
function setUpMockMethod(mockControl, scope, funcName, parameters,
return_values) {
var mockMethod = mockControl.createMethodMock(scope, funcName);
if (return_values) {
for (var i = 0, return_value; return_value = return_values[i]; i++) {
if (parameters && i < parameters.length) {
mockMethod(parameters[i]).$returns(return_value);
}
else {
mockMethod().$returns(return_value);
}
}
}
// If there are no return values but there are parameters, we are only
// recording specific method calls.
else if (parameters) {
for (var i = 0; i < parameters.length; i++) {
mockMethod(parameters[i]);
}
}
mockMethod.$replay();
return mockMethod;
}
/**
* Check if a variable with the given values exists.
* @param {Blockly.Workspace|Blockly.VariableMap} container The workspace or
* variableMap the checked variable belongs to.
* @param {!string} name The expected name of the variable.
* @param {!string} type The expected type of the variable.
* @param {!string} id The expected id of the variable.
*/
function checkVariableValues(container, name, type, id) {
var variable = container.getVariableById(id);
assertNotUndefined(variable);
assertEquals(name, variable.name);
assertEquals(type, variable.type);
assertEquals(id, variable.getId());
}

View file

@ -24,31 +24,20 @@ goog.require('goog.testing.MockControl');
var variable_map;
var mockControl_;
var workspace;
function variableMapTest_setUp() {
variable_map = new Blockly.VariableMap();
workspace = new Blockly.Workspace();
variable_map = new Blockly.VariableMap(workspace);
mockControl_ = new goog.testing.MockControl();
}
function variableMapTest_tearDown() {
workspace.dispose();
mockControl_.$tearDown();
variable_map = null;
}
/**
* Check if a variable with the given values exists.
* @param {!string} name The expected name of the variable.
* @param {!string} type The expected type of the variable.
* @param {!string} id The expected id of the variable.
*/
function variableMapTest_checkVariableValues(name, type, id) {
var variable = variable_map.getVariable(name);
assertNotUndefined(variable);
assertEquals(name, variable.name);
assertEquals(type, variable.type);
assertEquals(id, variable.getId());
}
function test_getVariable_Trivial() {
variableMapTest_setUp();
var var_1 = variable_map.createVariable('name1', 'type1', 'id1');
@ -96,14 +85,14 @@ function test_getVariableById_NotFound() {
function test_createVariableTrivial() {
variableMapTest_setUp();
variable_map.createVariable('name1', 'type1', 'id1');
variableMapTest_checkVariableValues('name1', 'type1', 'id1')
checkVariableValues(variable_map, 'name1', 'type1', 'id1');
variableMapTest_tearDown();
}
function test_createVariableAlreadyExists() {
// Expect that when the variable already exists, the variableMap_ is unchanged.
variableMapTest_setUp();
var var_1 = variable_map.createVariable('name1', 'type1', 'id1');
variable_map.createVariable('name1', 'type1', 'id1');
// Assert there is only one variable in the variable_map.
var keys = Object.keys(variable_map.variableMap_);
@ -112,7 +101,7 @@ function test_createVariableAlreadyExists() {
assertEquals(1, varMapLength);
variable_map.createVariable('name1');
variableMapTest_checkVariableValues('name1', 'type1', 'id1');
checkVariableValues(variable_map, 'name1', 'type1', 'id1');
// Check that the size of the variableMap_ did not change.
keys = Object.keys(variable_map.variableMap_);
assertEquals(1, keys.length);
@ -126,18 +115,17 @@ function test_createVariableNullAndUndefinedType() {
variable_map.createVariable('name1', null, 'id1');
variable_map.createVariable('name2', undefined, 'id2');
variableMapTest_checkVariableValues('name1', '', 'id1');
variableMapTest_checkVariableValues('name2', '', 'id2');
checkVariableValues(variable_map, 'name1', '', 'id1');
checkVariableValues(variable_map, 'name2', '', 'id2');
variableMapTest_tearDown();
}
function test_createVariableNullId() {
variableMapTest_setUp();
var mockGenUid = setUpMockMethod(Blockly.utils, 'genUid', null, '1');
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']);
try {
variable_map.createVariable('name1', 'type1', null);
mockGenUid.$verify();
variableMapTest_checkVariableValues('name1', 'type1', '1');
checkVariableValues(variable_map, 'name1', 'type1', '1');
}
finally {
variableMapTest_tearDown();
@ -146,11 +134,10 @@ function test_createVariableNullId() {
function test_createVariableUndefinedId() {
variableMapTest_setUp();
var mockGenUid = setUpMockMethod(Blockly.utils, 'genUid', null, '1');
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']);
try {
variable_map.createVariable('name1', 'type1', undefined);
mockGenUid.$verify();
variableMapTest_checkVariableValues('name1', 'type1', '1');
checkVariableValues(variable_map, 'name1', 'type1', '1');
}
finally {
variableMapTest_tearDown();
@ -192,8 +179,8 @@ function test_createVariableTwoSameTypes() {
variable_map.createVariable('name1', 'type1', 'id1');
variable_map.createVariable('name2', 'type1', 'id2');
variableMapTest_checkVariableValues('name1', 'type1', 'id1');
variableMapTest_checkVariableValues('name2', 'type1', 'id2');
checkVariableValues(variable_map, 'name1', 'type1', 'id1');
checkVariableValues(variable_map, 'name2', 'type1', 'id2');
variableMapTest_tearDown();
}
@ -205,8 +192,8 @@ function test_getVariablesOfType_Trivial() {
variable_map.createVariable('name4', 'type3', 'id4');
var result_array_1 = variable_map.getVariablesOfType('type1');
var result_array_2 = variable_map.getVariablesOfType('type5');
this.isEqualArrays([var_1, var_2], result_array_1);
this.isEqualArrays([], result_array_2);
isEqualArrays([var_1, var_2], result_array_1);
isEqualArrays([], result_array_2);
variableMapTest_tearDown();
}
@ -217,7 +204,7 @@ function test_getVariablesOfType_Null() {
var var_3 = variable_map.createVariable('name3', '', 'id3');
variable_map.createVariable('name4', 'type1', 'id4');
var result_array = variable_map.getVariablesOfType(null);
this.isEqualArrays([var_1, var_2, var_3], result_array);
isEqualArrays([var_1, var_2, var_3], result_array);
variableMapTest_tearDown();
}
@ -226,7 +213,7 @@ function test_getVariablesOfType_EmptyString() {
var var_1 = variable_map.createVariable('name1', null, 'id1');
var var_2 = variable_map.createVariable('name2', null, 'id2');
var result_array = variable_map.getVariablesOfType('');
this.isEqualArrays([var_1, var_2], result_array);
isEqualArrays([var_1, var_2], result_array);
variableMapTest_tearDown();
}
@ -235,14 +222,14 @@ function test_getVariablesOfType_Deleted() {
var variable = variable_map.createVariable('name1', null, 'id1');
variable_map.deleteVariable(variable);
var result_array = variable_map.getVariablesOfType('');
this.isEqualArrays([], result_array);
isEqualArrays([], result_array);
variableMapTest_tearDown();
}
function test_getVariablesOfType_DoesNotExist() {
variableMapTest_setUp();
var result_array = variable_map.getVariablesOfType('type1');
this.isEqualArrays([], result_array);
isEqualArrays([], result_array);
variableMapTest_tearDown();
}
@ -253,14 +240,14 @@ function test_getVariableTypes_Trivial() {
variable_map.createVariable('name3', 'type2', 'id3');
variable_map.createVariable('name4', 'type3', 'id4');
var result_array = variable_map.getVariableTypes();
this.isEqualArrays(['type1', 'type2', 'type3'], result_array);
isEqualArrays(['type1', 'type2', 'type3'], result_array);
variableMapTest_tearDown();
}
function test_getVariableTypes_None() {
variableMapTest_setUp();
var result_array = variable_map.getVariableTypes();
this.isEqualArrays([], result_array);
isEqualArrays([], result_array);
variableMapTest_tearDown();
}
@ -270,13 +257,13 @@ function test_getAllVariables_Trivial() {
var var_2 = variable_map.createVariable('name2', 'type1', 'id2');
var var_3 = variable_map.createVariable('name3', 'type2', 'id3');
var result_array = variable_map.getAllVariables();
this.isEqualArrays([var_1, var_2, var_3], result_array);
isEqualArrays([var_1, var_2, var_3], result_array);
variableMapTest_tearDown();
}
function test_getAllVariables_None() {
variableMapTest_setUp();
var result_array = variable_map.getAllVariables();
this.isEqualArrays([], result_array);
isEqualArrays([], result_array);
variableMapTest_tearDown();
}

View file

@ -25,8 +25,14 @@
'use strict';
var variable;
var workspace;
function variableTest_tearDown() {
function variableModelTest_setUp() {
workspace = new Blockly.Workspace();
}
function variableModelTest_tearDown() {
workspace.dispose();
variable = null;
}
@ -34,45 +40,52 @@ function variableTest_tearDown() {
* These tests check the constructor of the variable model.
*/
function testInit_Trivial() {
variable = new Blockly.VariableModel('test', 'test_type', 'test_id');
variableModelTest_setUp();
variable = new Blockly.VariableModel(workspace, 'test', 'test_type',
'test_id');
assertEquals('test', variable.name);
assertEquals('test_type', variable.type);
assertEquals('test_id', variable.id_);
variableTest_tearDown();
variableModelTest_tearDown();
}
function testInit_NullType() {
variable = new Blockly.VariableModel('test', null, 'test_id');
variableModelTest_setUp();
variable = new Blockly.VariableModel(workspace, 'test', null, 'test_id');
assertEquals('', variable.type);
variableTest_tearDown();
variableModelTest_tearDown();
}
function testInit_UndefinedType() {
variable = new Blockly.VariableModel('test', undefined, 'test_id');
variableModelTest_setUp();
variable = new Blockly.VariableModel(workspace, 'test', undefined, 'test_id');
assertEquals('', variable.type);
variableTest_tearDown();
variableModelTest_tearDown();
}
function testInit_NullId() {
variable = new Blockly.VariableModel('test', 'test_type', null);
variableModelTest_setUp();
variable = new Blockly.VariableModel(workspace, 'test', 'test_type', null);
assertEquals('test', variable.name);
assertEquals('test_type', variable.type);
assertNotNull(variable.id_);
variableTest_tearDown();
variableModelTest_tearDown();
}
function testInit_UndefinedId() {
variable = new Blockly.VariableModel('test', 'test_type', undefined);
variableModelTest_setUp();
variable = new Blockly.VariableModel(workspace, 'test', 'test_type', undefined);
assertEquals('test', variable.name);
assertEquals('test_type', variable.type);
assertNotNull(variable.id_);
variableTest_tearDown();
variableModelTest_tearDown();
}
function testInit_OnlyNameProvided() {
variable = new Blockly.VariableModel('test');
variableModelTest_setUp();
variable = new Blockly.VariableModel(workspace, 'test');
assertEquals('test', variable.name);
assertEquals('', variable.type);
assertNotNull(variable.id_);
variableTest_tearDown();
}
variableModelTest_tearDown();
}

View file

@ -24,16 +24,15 @@ goog.require('goog.testing.MockControl');
var workspace;
var mockControl_;
var saved_msg = Blockly.Msg.DELETE_VARIABLE;
Blockly.defineBlocksWithJsonArray([{
"type": "get_var_block",
"message0": "%1",
"args0": [
{
"type": "field_variable",
"name": "VAR",
}
]
"type": "get_var_block",
"message0": "%1",
"args0": [
{
"type": "field_variable",
"name": "VAR",
}
]
}]);
function workspaceTest_setUp() {
@ -41,25 +40,11 @@ function workspaceTest_setUp() {
mockControl_ = new goog.testing.MockControl();
}
function workspaceTest_setUpWithMockBlocks() {
workspaceTest_setUp();
// Need to define this because field_variable's dropdownCreate() calls replace
// on undefined value, Blockly.Msg.DELETE_VARIABLE. To fix this, define
// Blockly.Msg.DELETE_VARIABLE as %1 so the replace function finds the %1 it
// expects.
Blockly.Msg.DELETE_VARIABLE = '%1';
}
function workspaceTest_tearDown() {
mockControl_.$tearDown();
workspace.dispose();
}
function workspaceTest_tearDownWithMockBlocks() {
workspaceTest_tearDown();
Blockly.Msg.DELETE_VARIABLE = saved_msg;
}
/**
* Create a test get_var_block.
* @param {?string} variable_name The string to put into the variable field.
@ -71,53 +56,6 @@ function createMockBlock(variable_name) {
return block;
}
/**
* Check that two arrays have the same content.
* @param {!Array.<string>} array1 The first array.
* @param {!Array.<string>} array2 The second array.
*/
function isEqualArrays(array1, array2) {
assertEquals(array1.length, array2.length);
for (var i = 0; i < array1.length; i++) {
assertEquals(array1[i], array2[i]);
}
}
/**
* Check if a variable with the given values exists.
* @param {!string} name The expected name of the variable.
* @param {!string} type The expected type of the variable.
* @param {!string} id The expected id of the variable.
*/
function workspaceTest_checkVariableValues(name, type, id) {
var variable = workspace.getVariable(name);
assertNotUndefined(variable);
assertEquals(name, variable.name);
assertEquals(type, variable.type);
assertEquals(id, variable.getId());
}
/**
* Creates a controlled MethodMock. Set the expected return values. Set the
* method to replay.
* @param {!Object} scope The scope of the method to be mocked out.
* @param {!string} funcName The name of the function we're going to mock.
* @param {Object} parameters The parameters to call the mock with.
* @param {!Object} return_value The value to return when called.
* @return {!goog.testing.MockInterface} The mocked method.
*/
function setUpMockMethod(scope, funcName, parameters, return_value) {
var mockMethod = mockControl_.createMethodMock(scope, funcName);
if (parameters) {
mockMethod(parameters).$returns(return_value);
}
else {
mockMethod().$returns(return_value);
}
mockMethod.$replay();
return mockMethod;
}
function test_emptyWorkspace() {
workspaceTest_setUp();
try {
@ -220,7 +158,7 @@ function test_getBlockById() {
}
function test_deleteVariable_InternalTrivial() {
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
var var_1 = workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
createMockBlock('name1');
@ -231,9 +169,9 @@ function test_deleteVariable_InternalTrivial() {
var variable = workspace.getVariable('name1');
var block_var_name = workspace.topBlocks_[0].getVars()[0];
assertNull(variable);
workspaceTest_checkVariableValues('name2', 'type2', 'id2');
checkVariableValues(workspace, 'name2', 'type2', 'id2');
assertEquals('name2', block_var_name);
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}
// TODO(marisaleung): Test the alert for deleting a variable that is a procedure.
@ -242,14 +180,13 @@ function test_updateVariableStore_TrivialNoClear() {
workspaceTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
var mockAllUsedVariables = setUpMockMethod(Blockly.Variables,
'allUsedVariables', workspace, ['name1', 'name2']);
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables',
[workspace], [['name1', 'name2']]);
try {
workspace.updateVariableStore();
mockAllUsedVariables.$verify();
workspaceTest_checkVariableValues('name1', 'type1', 'id1');
workspaceTest_checkVariableValues('name2', 'type2', 'id2');
checkVariableValues(workspace, 'name1', 'type1', 'id1');
checkVariableValues(workspace, 'name2', 'type2', 'id2');
}
finally {
workspaceTest_tearDown();
@ -258,13 +195,13 @@ function test_updateVariableStore_TrivialNoClear() {
function test_updateVariableStore_NameNotInvariableMap_NoClear() {
workspaceTest_setUp();
setUpMockMethod(Blockly.Variables, 'allUsedVariables', workspace, ['name1']);
setUpMockMethod(Blockly.utils, 'genUid', null, '1');
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables',
[workspace], [['name1']]);
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
try {
workspace.updateVariableStore();
mockControl_.$verifyAll();
workspaceTest_checkVariableValues('name1', '', '1');
checkVariableValues(workspace, 'name1', '', '1');
}
finally {
workspaceTest_tearDown();
@ -275,14 +212,13 @@ function test_updateVariableStore_ClearAndAllInUse() {
workspaceTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
var mockAllUsedVariables = setUpMockMethod(Blockly.Variables,
'allUsedVariables', workspace, ['name1', 'name2']);
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables',
[workspace], [['name1', 'name2']]);
try {
workspace.updateVariableStore(true);
mockAllUsedVariables.$verify();
workspaceTest_checkVariableValues('name1', 'type1', 'id1');
workspaceTest_checkVariableValues('name2', 'type2', 'id2');
checkVariableValues(workspace, 'name1', 'type1', 'id1');
checkVariableValues(workspace, 'name2', 'type2', 'id2');
}
finally {
workspaceTest_tearDown();
@ -293,13 +229,12 @@ function test_updateVariableStore_ClearAndOneInUse() {
workspaceTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
var mockAllUsedVariables = setUpMockMethod(Blockly.Variables,
'allUsedVariables', workspace, ['name1']);
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables',
[workspace], [['name1']]);
try {
workspace.updateVariableStore(true);
mockAllUsedVariables.$verify();
workspaceTest_checkVariableValues('name1', 'type1', 'id1');
checkVariableValues(workspace, 'name1', 'type1', 'id1');
var variabe = workspace.getVariable('name2');
assertNull(variable);
}
@ -309,20 +244,20 @@ function test_updateVariableStore_ClearAndOneInUse() {
}
function test_addTopBlock_TrivialFlyoutIsTrue() {
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
workspace.isFlyout = true;
var block = createMockBlock();
workspace.removeTopBlock(block);
setUpMockMethod(Blockly.Variables, 'allUsedVariables', block, ['name1']);
setUpMockMethod(Blockly.utils, 'genUid', null, '1');
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables', [block],
[['name1']]);
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
try {
workspace.addTopBlock(block);
mockControl_.$verifyAll();
workspaceTest_checkVariableValues('name1', '', '1');
checkVariableValues(workspace, 'name1', '', '1');
}
finally {
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}
}
@ -330,14 +265,11 @@ function test_clear_Trivial() {
workspaceTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
var mockSetGroup = mockControl_.createMethodMock(Blockly.Events, 'setGroup');
mockSetGroup(true);
mockSetGroup(false);
mockSetGroup.$replay();
setUpMockMethod(mockControl_, Blockly.Events, 'setGroup', [true, false],
null);
try {
workspace.clear();
mockControl_.$verifyAll();
var topBlocks_length = workspace.topBlocks_.length;
var varMapLength = Object.keys(workspace.variableMap_.variableMap_).length;
assertEquals(0, topBlocks_length);
@ -350,14 +282,11 @@ function test_clear_Trivial() {
function test_clear_NoVariables() {
workspaceTest_setUp();
var mockSetGroup = mockControl_.createMethodMock(Blockly.Events, 'setGroup');
mockSetGroup(true);
mockSetGroup(false);
mockSetGroup.$replay();
setUpMockMethod(mockControl_, Blockly.Events, 'setGroup', [true, false],
null);
try {
workspace.clear();
mockSetGroup.$verify();
var topBlocks_length = workspace.topBlocks_.length;
var varMapLength = Object.keys(workspace.variableMap_.variableMap_).length;
assertEquals(0, topBlocks_length);
@ -373,18 +302,14 @@ function test_renameVariable_NoBlocks() {
workspaceTest_setUp();
var oldName = 'name1';
var newName = 'name2';
var mockSetGroup = mockControl_.createMethodMock(Blockly.Events, 'setGroup');
var mockGenUid = mockControl_.createMethodMock(Blockly.utils, 'genUid');
// Mocked setGroup to ensure only one call to the mocked genUid.
mockSetGroup(true);
mockSetGroup(false);
mockGenUid().$returns('1');
mockControl_.$replayAll();
// Mocked setGroup to ensure only one call to the mocked genUid.
setUpMockMethod(mockControl_, Blockly.Events, 'setGroup', [true, false],
null);
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
try {
workspace.renameVariable(oldName, newName);
mockControl_.$verifyAll();
workspaceTest_checkVariableValues('name2', '', '1');
checkVariableValues(workspace, 'name2', '', '1');
var variable = workspace.getVariable(oldName);
assertNull(variable);
}
@ -395,36 +320,36 @@ function test_renameVariable_NoBlocks() {
function test_renameVariable_SameNameNoBlocks() {
// Expect 'renameVariable' to create new variable with newName.
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
var name = 'name1';
workspace.createVariable(name, 'type1', 'id1');
workspace.renameVariable(name, name);
workspaceTest_checkVariableValues(name, 'type1', 'id1');
workspaceTest_tearDownWithMockBlocks();
checkVariableValues(workspace, name, 'type1', 'id1');
workspaceTest_tearDown();
}
function test_renameVariable_OnlyOldNameBlockExists() {
// Expect 'renameVariable' to change oldName variable name to newName.
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
var oldName = 'name1';
var newName = 'name2';
workspace.createVariable(oldName, 'type1', 'id1');
createMockBlock(oldName);
workspace.renameVariable(oldName, newName);
workspaceTest_checkVariableValues(newName, 'type1', 'id1');
checkVariableValues(workspace, newName, 'type1', 'id1');
var variable = workspace.getVariable(oldName);
var block_var_name = workspace.topBlocks_[0].getVars()[0];
assertNull(variable);
assertEquals(newName, block_var_name);
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}
function test_renameVariable_TwoVariablesSameType() {
// Expect 'renameVariable' to change oldName variable name to newName.
// Expect oldName block name to change to newName
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
var oldName = 'name1';
var newName = 'name2';
workspace.createVariable(oldName, 'type1', 'id1');
@ -433,19 +358,19 @@ function test_renameVariable_TwoVariablesSameType() {
createMockBlock(newName);
workspace.renameVariable(oldName, newName);
workspaceTest_checkVariableValues(newName, 'type1', 'id2');
checkVariableValues(workspace, newName, 'type1', 'id2');
var variable = workspace.getVariable(oldName);
var block_var_name_1 = workspace.topBlocks_[0].getVars()[0];
var block_var_name_2 = workspace.topBlocks_[1].getVars()[0];
assertNull(variable);
assertEquals(newName, block_var_name_1);
assertEquals(newName, block_var_name_2);
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}
function test_renameVariable_TwoVariablesDifferentType() {
// Expect triggered error because of different types
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
var oldName = 'name1';
var newName = 'name2';
workspace.createVariable(oldName, 'type1', 'id1');
@ -459,33 +384,33 @@ function test_renameVariable_TwoVariablesDifferentType() {
} catch (e) {
// expected
}
workspaceTest_checkVariableValues(oldName, 'type1', 'id1');
workspaceTest_checkVariableValues(newName, 'type2', 'id2');
checkVariableValues(workspace, oldName, 'type1', 'id1');
checkVariableValues(workspace, newName, 'type2', 'id2');
var block_var_name_1 = workspace.topBlocks_[0].getVars()[0];
var block_var_name_2 = workspace.topBlocks_[1].getVars()[0];
assertEquals(oldName, block_var_name_1);
assertEquals(newName, block_var_name_2);
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}
function test_renameVariable_OldCase() {
// Expect triggered error because of different types
workspaceTest_setUpWithMockBlocks();
workspaceTest_setUp();
var oldCase = 'Name1';
var newName = 'name1';
workspace.createVariable(oldCase, 'type1', 'id1');
createMockBlock(oldCase);
workspace.renameVariable(oldCase, newName);
workspaceTest_checkVariableValues(newName, 'type1', 'id1');
var result_oldCase = workspace.getVariable(oldCase).name
checkVariableValues(workspace, newName, 'type1', 'id1');
var result_oldCase = workspace.getVariable(oldCase).name;
assertNotEquals(oldCase, result_oldCase);
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}
function test_renameVariable_TwoVariablesAndOldCase() {
// Expect triggered error because of different types
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
var oldName = 'name1';
var oldCase = 'Name2';
var newName = 'name2';
@ -496,7 +421,7 @@ function test_renameVariable_TwoVariablesAndOldCase() {
workspace.renameVariable(oldName, newName);
workspaceTest_checkVariableValues(newName, 'type1', 'id2');
checkVariableValues(workspace, newName, 'type1', 'id2');
var variable = workspace.getVariable(oldName);
var result_oldCase = workspace.getVariable(oldCase).name;
var block_var_name_1 = workspace.topBlocks_[0].getVars()[0];
@ -505,7 +430,7 @@ function test_renameVariable_TwoVariablesAndOldCase() {
assertNotEquals(oldCase, result_oldCase);
assertEquals(newName, block_var_name_1);
assertEquals(newName, block_var_name_2);
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}
// Extra testing not required for renameVariableById. It calls renameVariable
@ -513,7 +438,7 @@ function test_renameVariable_TwoVariablesAndOldCase() {
function test_renameVariableById_TwoVariablesSameType() {
// Expect 'renameVariableById' to change oldName variable name to newName.
// Expect oldName block name to change to newName
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
var oldName = 'name1';
var newName = 'name2';
workspace.createVariable(oldName, 'type1', 'id1');
@ -522,44 +447,44 @@ function test_renameVariableById_TwoVariablesSameType() {
createMockBlock(newName);
workspace.renameVariableById('id1', newName);
workspaceTest_checkVariableValues(newName, 'type1', 'id2');
var variable = workspace.getVariable(oldName)
checkVariableValues(workspace, newName, 'type1', 'id2');
var variable = workspace.getVariable(oldName);
var block_var_name_1 = workspace.topBlocks_[0].getVars()[0];
var block_var_name_2 = workspace.topBlocks_[1].getVars()[0];
assertNull(variable);
assertEquals(newName, block_var_name_1);
assertEquals(newName, block_var_name_2);
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}
function test_deleteVariable_Trivial() {
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type1', 'id2');
createMockBlock('name1');
createMockBlock('name2');
workspace.deleteVariable('name1');
workspaceTest_checkVariableValues('name2', 'type1', 'id2');
checkVariableValues(workspace, 'name2', 'type1', 'id2');
var variable = workspace.getVariable('name1');
var block_var_name = workspace.topBlocks_[0].getVars()[0];
assertNull(variable);
assertEquals('name2', block_var_name);
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}
function test_deleteVariableById_Trivial() {
workspaceTest_setUpWithMockBlocks()
workspaceTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type1', 'id2');
createMockBlock('name1');
createMockBlock('name2');
workspace.deleteVariableById('id1');
workspaceTest_checkVariableValues('name2', 'type1', 'id2');
checkVariableValues(workspace, 'name2', 'type1', 'id2');
var variable = workspace.getVariable('name1');
var block_var_name = workspace.topBlocks_[0].getVars()[0];
assertNull(variable);
assertEquals('name2', block_var_name);
workspaceTest_tearDownWithMockBlocks();
workspaceTest_tearDown();
}

View file

@ -0,0 +1,417 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2017 Google Inc.
* https://developers.google.com/blockly/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Tests for Blockly.Workspace.undo.
* @author marisaleung@google.com (Marisa Leung)
*/
'use strict';
goog.require('goog.events.EventHandler');
goog.require('goog.testing');
goog.require('goog.testing.events');
goog.require('goog.testing.MockControl');
var workspace;
var mockControl_;
var savedFireFunc = Blockly.Events.fire;
Blockly.defineBlocksWithJsonArray([{
"type": "get_var_block",
"message0": "%1",
"args0": [
{
"type": "field_variable",
"name": "VAR",
}
]
}]);
function temporary_fireEvent(event) {
if (!Blockly.Events.isEnabled()) {
return;
}
Blockly.Events.FIRE_QUEUE_.push(event);
Blockly.Events.fireNow_();
}
function undoRedoTest_setUp() {
workspace = new Blockly.Workspace();
mockControl_ = new goog.testing.MockControl();
Blockly.Events.fire = temporary_fireEvent;
}
function undoRedoTest_tearDown() {
mockControl_.$tearDown();
workspace.dispose();
Blockly.Events.fire = savedFireFunc;
}
/**
* Create a test get_var_block.
* @param {string} variableName The string to put into the variable field.
* @return {!Blockly.Block} The created block.
*/
function createMockBlock(variableName) {
var block = new Blockly.Block(workspace, 'get_var_block');
block.inputList[0].fieldRow[0].setValue(variableName);
return block;
}
/**
* Check that the top block with the given index contains a variable with
* the given name.
* @param {number} blockIndex The index of the top block.
* @param {string} name The expected name of the variable in the block.
*/
function undoRedoTest_checkBlockVariableName(blockIndex, name) {
var blockVarName = workspace.topBlocks_[blockIndex].getVars()[0];
assertEquals(name, blockVarName);
}
function createTwoVarsEmptyType() {
workspace.createVariable('name1', '', 'id1');
workspace.createVariable('name2', '', 'id2');
}
function test_undoCreateVariable_Trivial() {
undoRedoTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
workspace.undo();
checkVariableValues(workspace, 'name1', 'type1', 'id1');
assertNull(workspace.getVariableById('id2'));
workspace.undo();
assertNull(workspace.getVariableById('id1'));
assertNull(workspace.getVariableById('id2'));
undoRedoTest_tearDown();
}
function test_redoAndUndoCreateVariable_Trivial() {
undoRedoTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
workspace.undo();
workspace.undo(true);
// Expect that variable 'id2' is recreated
checkVariableValues(workspace, 'name1', 'type1', 'id1');
checkVariableValues(workspace, 'name2', 'type2', 'id2');
workspace.undo();
workspace.undo();
workspace.undo(true);
// Expect that variable 'id1' is recreated
checkVariableValues(workspace, 'name1', 'type1', 'id1');
assertNull(workspace.getVariableById('id2'));
undoRedoTest_tearDown();
}
function test_undoDeleteVariable_NoBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
workspace.deleteVariableById('id1');
workspace.deleteVariableById('id2');
workspace.undo();
assertNull(workspace.getVariableById('id1'));
checkVariableValues(workspace, 'name2', 'type2', 'id2');
workspace.undo();
checkVariableValues(workspace, 'name1', 'type1', 'id1');
checkVariableValues(workspace, 'name2', 'type2', 'id2');
undoRedoTest_tearDown();
}
function test_undoDeleteVariable_WithBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
createMockBlock('name1');
createMockBlock('name2');
workspace.deleteVariableById('id1');
workspace.deleteVariableById('id2');
workspace.undo();
undoRedoTest_checkBlockVariableName(0, 'name2');
assertNull(workspace.getVariableById('id1'));
checkVariableValues(workspace, 'name2', 'type2', 'id2');
workspace.undo();
undoRedoTest_checkBlockVariableName(0, 'name2');
undoRedoTest_checkBlockVariableName(1, 'name1');
checkVariableValues(workspace, 'name1', 'type1', 'id1');
checkVariableValues(workspace, 'name2', 'type2', 'id2');
undoRedoTest_tearDown();
}
function test_redoAndUndoDeleteVariable_NoBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
workspace.deleteVariableById('id1');
workspace.deleteVariableById('id2');
workspace.undo();
workspace.undo(true);
// Expect that both variables are deleted
assertNull(workspace.getVariableById('id1'));
assertNull(workspace.getVariableById('id2'));
workspace.undo();
workspace.undo();
workspace.undo(true);
// Expect that variable 'id2' is recreated
assertNull(workspace.getVariableById('id1'));
checkVariableValues(workspace, 'name2', 'type2', 'id2');
undoRedoTest_tearDown();
}
function test_redoAndUndoDeleteVariable_WithBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');
createMockBlock('name1');
createMockBlock('name2');
workspace.deleteVariableById('id1');
workspace.deleteVariableById('id2');
workspace.undo();
workspace.undo(true);
// Expect that both variables are deleted
assertEquals(0, workspace.topBlocks_.length);
assertNull(workspace.getVariableById('id1'));
assertNull(workspace.getVariableById('id2'));
workspace.undo();
workspace.undo();
workspace.undo(true);
// Expect that variable 'id2' is recreated
undoRedoTest_checkBlockVariableName(0, 'name2');
assertNull(workspace.getVariableById('id1'));
checkVariableValues(workspace, 'name2', 'type2', 'id2');
undoRedoTest_tearDown();
}
function test_redoAndUndoDeleteVariableTwice_NoBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
workspace.deleteVariableById('id1');
workspace.deleteVariableById('id1');
// Check the undoStack only recorded one delete event.
var undoStack = workspace.undoStack_;
assertEquals('var_delete', undoStack[undoStack.length-1].type);
assertNotEquals('var_delete', undoStack[undoStack.length-2].type);
// undo delete
workspace.undo();
checkVariableValues(workspace, 'name1', 'type1', 'id1');
// redo delete
workspace.undo(true);
assertNull(workspace.getVariableById('id1'));
// redo delete, nothing should happen
workspace.undo(true);
assertNull(workspace.getVariableById('id1'));
undoRedoTest_tearDown();
}
function test_redoAndUndoDeleteVariableTwice_WithBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', 'type1', 'id1');
createMockBlock('name1');
workspace.deleteVariableById('id1');
workspace.deleteVariableById('id1');
// Check the undoStack only recorded one delete event.
var undoStack = workspace.undoStack_;
assertEquals('var_delete', undoStack[undoStack.length-1].type);
assertEquals('delete', undoStack[undoStack.length-2].type);
assertNotEquals('var_delete', undoStack[undoStack.length-3].type);
// undo delete
workspace.undo();
undoRedoTest_checkBlockVariableName(0, 'name1');
checkVariableValues(workspace, 'name1', 'type1', 'id1');
// redo delete
workspace.undo(true);
assertEquals(0, workspace.topBlocks_.length);
assertNull(workspace.getVariableById('id1'));
// redo delete, nothing should happen
workspace.undo(true);
assertEquals(0, workspace.topBlocks_.length);
assertNull(workspace.getVariableById('id1'));
undoRedoTest_tearDown();
}
function test_undoRedoRenameVariable_NeitherVariableExists() {
// Expect that a variable with the name, 'name2', and the generated UUID,
// 'id2', to be created when rename is called. Undo removes this variable
// and redo recreates it.
undoRedoTest_setUp();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null,
['rename_group', 'id2', 'delete_group']);
workspace.renameVariable('name1', 'name2');
workspace.undo();
assertNull(workspace.getVariableById('id2'));
workspace.undo(true);
checkVariableValues(workspace, 'name2', '', 'id2');
undoRedoTest_tearDown();
}
function test_undoRedoRenameVariable_OneExists_NoBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', '', 'id1');
workspace.renameVariable('name1', 'name2');
workspace.undo();
checkVariableValues(workspace, 'name1', '', 'id1');
assertNull(workspace.getVariable('name2'));
workspace.undo(true);
checkVariableValues(workspace, 'name2', '', 'id1');
undoRedoTest_tearDown();
}
function test_undoRedoRenameVariable_OneExists_WithBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', '', 'id1');
createMockBlock('name1');
workspace.renameVariable('name1', 'name2');
workspace.undo();
undoRedoTest_checkBlockVariableName(0, 'name1');
checkVariableValues(workspace, 'name1', '', 'id1');
assertNull(workspace.getVariable('name2'));
workspace.undo(true);
checkVariableValues(workspace, 'name2', '', 'id1');
undoRedoTest_checkBlockVariableName(0, 'name2');
undoRedoTest_tearDown();
}
function test_undoRedoRenameVariable_BothExist_NoBlocks() {
undoRedoTest_setUp();
createTwoVarsEmptyType();
workspace.renameVariable('name1', 'name2');
workspace.undo();
checkVariableValues(workspace, 'name1', '', 'id1');
checkVariableValues(workspace, 'name2', '', 'id2');
workspace.undo(true);
checkVariableValues(workspace, 'name2', '', 'id2');
assertNull(workspace.getVariable('name1'));
undoRedoTest_tearDown();
}
function test_undoRedoRenameVariable_BothExist_WithBlocks() {
undoRedoTest_setUp();
createTwoVarsEmptyType();
createMockBlock('name1');
createMockBlock('name2');
workspace.renameVariable('name1', 'name2');
workspace.undo();
undoRedoTest_checkBlockVariableName(0, 'name1');
undoRedoTest_checkBlockVariableName(1, 'name2');
checkVariableValues(workspace, 'name1', '', 'id1');
checkVariableValues(workspace, 'name2', '', 'id2');
workspace.undo(true);
undoRedoTest_checkBlockVariableName(0, 'name2');
undoRedoTest_checkBlockVariableName(1, 'name2');
undoRedoTest_tearDown();
}
function test_undoRedoRenameVariable_BothExistCaseChange_NoBlocks() {
undoRedoTest_setUp();
createTwoVarsEmptyType();
workspace.renameVariable('name1', 'Name2');
workspace.undo();
checkVariableValues(workspace, 'name1', '', 'id1');
checkVariableValues(workspace, 'name2', '', 'id2');
workspace.undo(true);
checkVariableValues(workspace, 'Name2', '', 'id2');
assertNull(workspace.getVariable('name1'));
undoRedoTest_tearDown();
}
function test_undoRedoRenameVariable_BothExistCaseChange_WithBlocks() {
undoRedoTest_setUp();
createTwoVarsEmptyType();
createMockBlock('name1');
createMockBlock('name2');
workspace.renameVariable('name1', 'Name2');
workspace.undo();
undoRedoTest_checkBlockVariableName(0, 'name1');
undoRedoTest_checkBlockVariableName(1, 'name2');
checkVariableValues(workspace, 'name1', '', 'id1');
checkVariableValues(workspace, 'name2', '', 'id2');
workspace.undo(true);
checkVariableValues(workspace, 'Name2', '', 'id2');
assertNull(workspace.getVariable('name1'));
undoRedoTest_checkBlockVariableName(0, 'Name2');
undoRedoTest_checkBlockVariableName(1, 'Name2');
undoRedoTest_tearDown();
}
function test_undoRedoRenameVariable_OnlyCaseChange_NoBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', '', 'id1');
workspace.renameVariable('name1', 'Name1');
workspace.undo();
checkVariableValues(workspace, 'name1', '', 'id1');
workspace.undo(true);
checkVariableValues(workspace, 'Name1', '', 'id1');
undoRedoTest_tearDown();
}
function test_undoRedoRenameVariable_OnlyCaseChange_WithBlocks() {
undoRedoTest_setUp();
workspace.createVariable('name1', '', 'id1');
createMockBlock('name1');
workspace.renameVariable('name1', 'Name1');
workspace.undo();
undoRedoTest_checkBlockVariableName(0, 'name1');
checkVariableValues(workspace, 'name1', '', 'id1');
workspace.undo(true);
checkVariableValues(workspace, 'Name1', '', 'id1');
undoRedoTest_checkBlockVariableName(0, 'Name1');
undoRedoTest_tearDown();
}

View file

@ -23,7 +23,6 @@ goog.require('goog.testing');
goog.require('goog.testing.MockControl');
var mockControl_;
var saved_msg = Blockly.Msg.DELETE_VARIABLE;
var workspace;
var XML_TEXT = ['<xml xmlns="http://www.w3.org/1999/xhtml">',
' <block type="controls_repeat_ext" inline="true" x="21" y="23">',
@ -70,11 +69,6 @@ function xmlTest_setUpWithMockBlocks() {
}
],
}]);
// Need to define this because field_variable's dropdownCreate() calls replace
// on undefined value, Blockly.Msg.DELETE_VARIABLE. To fix this, define
// Blockly.Msg.DELETE_VARIABLE as %1 so the replace function finds the %1 it
// expects.
Blockly.Msg.DELETE_VARIABLE = '%1';
}
function xmlTest_tearDown() {
@ -85,7 +79,6 @@ function xmlTest_tearDown() {
function xmlTest_tearDownWithMockBlocks() {
xmlTest_tearDown();
delete Blockly.Blocks.field_variable_test_block;
Blockly.Msg.DELETE_VARIABLE = saved_msg;
}
/**
@ -129,20 +122,6 @@ function xmlTest_checkVariableDomValues(variableDom, type, id, text) {
assertEquals(text, variableDom.textContent);
}
/**
* Check if a variable with the given values exists.
* @param {!string} name The expected name of the variable.
* @param {!string} type The expected type of the variable.
* @param {!string} id The expected id of the variable.
*/
function xmlTest_checkVariableValues(name, type, id) {
var variable = workspace.getVariable(name);
assertNotUndefined(variable);
assertEquals(name, variable.name);
assertEquals(type, variable.type);
assertEquals(id, variable.getId());
}
function test_textToDom() {
var dom = Blockly.Xml.textToDom(XML_TEXT);
assertEquals('XML tag', 'xml', dom.nodeName);
@ -159,10 +138,7 @@ function test_domToText() {
function test_domToWorkspace_BackwardCompatibility() {
// Expect that workspace still loads without serialized variables.
xmlTest_setUpWithMockBlocks();
var mockGenUid = mockControl_.createMethodMock(Blockly.utils, 'genUid');
mockGenUid().$returns('1');
mockGenUid().$returns('1');
mockGenUid().$replay();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '1']);
try {
var dom = Blockly.Xml.textToDom(
'<xml>' +
@ -172,7 +148,7 @@ function test_domToWorkspace_BackwardCompatibility() {
'</xml>');
Blockly.Xml.domToWorkspace(dom, workspace);
assertEquals('Block count', 1, workspace.getAllBlocks().length);
xmlTest_checkVariableValues('name1', '', '1');
checkVariableValues(workspace, 'name1', '', '1');
} finally {
xmlTest_tearDownWithMockBlocks();
}
@ -195,9 +171,9 @@ function test_domToWorkspace_VariablesAtTop() {
'</xml>');
Blockly.Xml.domToWorkspace(dom, workspace);
assertEquals('Block count', 1, workspace.getAllBlocks().length);
xmlTest_checkVariableValues('name1', 'type1', 'id1');
xmlTest_checkVariableValues('name2', 'type2', 'id2');
xmlTest_checkVariableValues('name3', '', 'id3');
checkVariableValues(workspace, 'name1', 'type1', 'id1');
checkVariableValues(workspace, 'name2', 'type2', 'id2');
checkVariableValues(workspace, 'name3', '', 'id3');
} finally {
xmlTest_tearDownWithMockBlocks();
}
@ -309,27 +285,26 @@ function test_appendDomToWorkspace() {
}
function test_blockToDom_fieldToDom_trivial() {
xmlTest_setUpWithMockBlocks()
xmlTest_setUpWithMockBlocks();
workspace.createVariable('name1', 'type1', 'id1');
var block = new Blockly.Block(workspace, 'field_variable_test_block');
block.inputList[0].fieldRow[0].setValue('name1');
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
xmlTest_checkVariableFieldDomValues(resultFieldDom, 'VAR', 'type1', 'id1', 'name1')
xmlTest_tearDownWithMockBlocks()
xmlTest_checkVariableFieldDomValues(resultFieldDom, 'VAR', 'type1', 'id1',
'name1');
xmlTest_tearDownWithMockBlocks();
}
function test_blockToDom_fieldToDom_defaultCase() {
xmlTest_setUpWithMockBlocks()
var mockGenUid = mockControl_.createMethodMock(Blockly.utils, 'genUid');
mockGenUid().$returns('1');
mockGenUid().$replay();
xmlTest_setUpWithMockBlocks();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '1']);
workspace.createVariable('name1');
var block = new Blockly.Block(workspace, 'field_variable_test_block');
block.inputList[0].fieldRow[0].setValue('name1');
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
// Expect type is '' and id is '1' since we don't specify type and id.
xmlTest_checkVariableFieldDomValues(resultFieldDom, 'VAR', '', '1', 'name1')
xmlTest_tearDownWithMockBlocks()
xmlTest_checkVariableFieldDomValues(resultFieldDom, 'VAR', '', '1', 'name1');
xmlTest_tearDownWithMockBlocks();
}
function test_blockToDom_fieldToDom_notAFieldVariable() {
@ -344,19 +319,17 @@ function test_blockToDom_fieldToDom_notAFieldVariable() {
}
],
}]);
xmlTest_setUpWithMockBlocks()
xmlTest_setUpWithMockBlocks();
var block = new Blockly.Block(workspace, 'field_angle_test_block');
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
xmlTest_checkNonVariableField(resultFieldDom, 'VAR', '90');
delete Blockly.Blocks.field_angle_block;
xmlTest_tearDownWithMockBlocks()
xmlTest_tearDownWithMockBlocks();
}
function test_variablesToDom_oneVariable() {
xmlTest_setUp();
var mockGenUid = mockControl_.createMethodMock(Blockly.utils, 'genUid');
mockGenUid().$returns('1');
mockGenUid().$replay();
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
workspace.createVariable('name1');
var resultDom = Blockly.Xml.variablesToDom(workspace.getAllVariables());
@ -392,34 +365,3 @@ function test_variablesToDom_noVariables() {
assertEquals(1, resultDom.children.length);
xmlTest_tearDown();
}
/**
* Tests the that appendDomToWorkspace works in a headless mode.
* Also see test_appendDomToWorkspace() in workspace_svg_test.js.
*/
function test_appendDomToWorkspace() {
Blockly.Blocks.test_block = {
init: function() {
this.jsonInit({
message0: 'test',
});
}
};
try {
var dom = Blockly.Xml.textToDom(
'<xml xmlns="http://www.w3.org/1999/xhtml">' +
' <block type="test_block" inline="true" x="21" y="23">' +
' </block>' +
'</xml>');
var workspace = new Blockly.Workspace();
Blockly.Xml.appendDomToWorkspace(dom, workspace);
assertEquals('Block count', 1, workspace.getAllBlocks().length);
var newBlockIds = Blockly.Xml.appendDomToWorkspace(dom, workspace);
assertEquals('Block count', 2, workspace.getAllBlocks().length);
assertEquals('Number of new block ids',1,newBlockIds.length);
} finally {
delete Blockly.Blocks.test_block;
workspace.dispose();
}
}