goog.editor.plugins.undoredomanager_test.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of google-closure-library
Show all versions of google-closure-library
The Google Closure Library is a collection of JavaScript code
designed for use with the Google Closure JavaScript Compiler.
This non-official distribution was prepared by the ClojureScript
team at http://clojure.org/
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// 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.
goog.provide('goog.editor.plugins.UndoRedoManagerTest');
goog.setTestOnly('goog.editor.plugins.UndoRedoManagerTest');
goog.require('goog.editor.plugins.UndoRedoManager');
goog.require('goog.editor.plugins.UndoRedoState');
goog.require('goog.events');
goog.require('goog.testing.StrictMock');
goog.require('goog.testing.jsunit');
var mockState1;
var mockState2;
var mockState3;
var states;
var manager;
var stateChangeCount;
var beforeUndoCount;
var beforeRedoCount;
var preventDefault;
function setUp() {
manager = new goog.editor.plugins.UndoRedoManager();
stateChangeCount = 0;
goog.events.listen(
manager, goog.editor.plugins.UndoRedoManager.EventType.STATE_CHANGE,
function() { stateChangeCount++; });
beforeUndoCount = 0;
preventDefault = false;
goog.events.listen(
manager, goog.editor.plugins.UndoRedoManager.EventType.BEFORE_UNDO,
function(e) {
beforeUndoCount++;
if (preventDefault) {
e.preventDefault();
}
});
beforeRedoCount = 0;
goog.events.listen(
manager, goog.editor.plugins.UndoRedoManager.EventType.BEFORE_REDO,
function(e) {
beforeRedoCount++;
if (preventDefault) {
e.preventDefault();
}
});
mockState1 = new goog.testing.StrictMock(goog.editor.plugins.UndoRedoState);
mockState2 = new goog.testing.StrictMock(goog.editor.plugins.UndoRedoState);
mockState3 = new goog.testing.StrictMock(goog.editor.plugins.UndoRedoState);
states = [mockState1, mockState2, mockState3];
mockState1.equals = mockState2.equals =
mockState3.equals = function(state) { return this == state; };
mockState1.isAsynchronous = mockState2.isAsynchronous =
mockState3.isAsynchronous = function() { return false; };
}
function tearDown() {
goog.events.removeAll(manager);
manager.dispose();
}
/**
* Adds all the mock states to the undo-redo manager.
*/
function addStatesToManager() {
manager.addState(states[0]);
for (var i = 1; i < states.length; i++) {
var state = states[i];
manager.addState(state);
}
stateChangeCount = 0;
}
/**
* Resets all mock states so that they are ready for testing.
*/
function resetStates() {
for (var i = 0; i < states.length; i++) {
states[i].$reset();
}
}
function testSetMaxUndoDepth() {
manager.setMaxUndoDepth(2);
addStatesToManager();
assertArrayEquals(
'Undo stack must contain only the two most recent states.',
[mockState2, mockState3], manager.undoStack_);
}
function testAddState() {
var stateAddedCount = 0;
goog.events.listen(
manager, goog.editor.plugins.UndoRedoManager.EventType.STATE_ADDED,
function() { stateAddedCount++; });
manager.addState(mockState1);
assertArrayEquals(
'Undo stack must contain added state.', [mockState1], manager.undoStack_);
assertEquals(
'Manager must dispatch one state change event on ' +
'undo stack 0->1 transition.',
1, stateChangeCount);
assertEquals('State added must have dispatched once.', 1, stateAddedCount);
mockState1.$reset();
// Test adding same state twice.
manager.addState(mockState1);
assertArrayEquals(
'Undo stack must not contain two equal, sequential states.', [mockState1],
manager.undoStack_);
assertEquals(
'Manager must not dispatch state change event when nothing is ' +
'added to the stack.',
1, stateChangeCount);
assertEquals('State added must have dispatched once.', 1, stateAddedCount);
// Test adding a second state.
manager.addState(mockState2);
assertArrayEquals(
'Undo stack must contain both states.', [mockState1, mockState2],
manager.undoStack_);
assertEquals(
'Manager must not dispatch state change event when second ' +
'state is added to the stack.',
1, stateChangeCount);
assertEquals('State added must have dispatched twice.', 2, stateAddedCount);
// Test adding a state when there is state on the redo stack.
manager.undo();
assertEquals(
'Manager must dispatch state change when redo stack goes to 1.', 2,
stateChangeCount);
manager.addState(mockState3);
assertArrayEquals(
'Undo stack must contain states 1 and 3.', [mockState1, mockState3],
manager.undoStack_);
assertEquals(
'Manager must dispatch state change event when redo stack ' +
'goes to zero.',
3, stateChangeCount);
assertEquals(
'State added must have dispatched three times.', 3, stateAddedCount);
}
function testHasState() {
assertFalse('New manager must have no undo state.', manager.hasUndoState());
assertFalse('New manager must have no redo state.', manager.hasRedoState());
manager.addState(mockState1);
assertTrue('Manager must have only undo state.', manager.hasUndoState());
assertFalse('Manager must have no redo state.', manager.hasRedoState());
manager.undo();
assertFalse('Manager must have no undo state.', manager.hasUndoState());
assertTrue('Manager must have only redo state.', manager.hasRedoState());
}
function testClearHistory() {
addStatesToManager();
manager.undo();
stateChangeCount = 0;
manager.clearHistory();
assertFalse('Undo stack must be empty.', manager.hasUndoState());
assertFalse('Redo stack must be empty.', manager.hasRedoState());
assertEquals(
'State change count must be 1 after clear history.', 1, stateChangeCount);
manager.clearHistory();
assertEquals(
'Repeated clearHistory must not change state change count.', 1,
stateChangeCount);
}
function testUndo() {
addStatesToManager();
mockState3.undo();
mockState3.$replay();
manager.undo();
assertEquals(
'Adding first item to redo stack must dispatch state change.', 1,
stateChangeCount);
assertEquals('Undo must cause before action to dispatch', 1, beforeUndoCount);
mockState3.$verify();
preventDefault = true;
mockState2.$replay();
manager.undo();
assertEquals(
'No stack transitions between 0 and 1, must not dispatch ' +
'state change.',
1, stateChangeCount);
assertEquals('Undo must cause before action to dispatch', 2, beforeUndoCount);
mockState2.$verify(); // Verify that undo was prevented.
preventDefault = false;
mockState1.undo();
mockState1.$replay();
manager.undo();
assertEquals(
'Doing last undo operation must dispatch state change.', 2,
stateChangeCount);
assertEquals('Undo must cause before action to dispatch', 3, beforeUndoCount);
mockState1.$verify();
}
function testUndo_Asynchronous() {
// Using a stub instead of a mock here so that the state can behave as an
// EventTarget and dispatch events.
var stubState = new goog.editor.plugins.UndoRedoState(true);
var undoCalled = false;
stubState.undo = function() { undoCalled = true; };
stubState.redo = goog.nullFunction;
stubState.equals = function() { return false; };
manager.addState(mockState2);
manager.addState(mockState1);
manager.addState(stubState);
manager.undo();
assertTrue('undoCalled must be true (undo must be called).', undoCalled);
assertEquals('Undo must cause before action to dispatch', 1, beforeUndoCount);
// Calling undo shouldn't actually undo since the first async undo hasn't
// fired an event yet.
mockState1.$replay();
manager.undo();
mockState1.$verify();
assertEquals(
'Before action must not dispatch for pending undo.', 1, beforeUndoCount);
// Dispatching undo completed on first undo, should cause the second pending
// undo to happen.
mockState1.$reset();
mockState1.undo();
mockState1.$replay();
mockState2.$replay(); // Nothing should happen to mockState2.
stubState.dispatchEvent(goog.editor.plugins.UndoRedoState.ACTION_COMPLETED);
mockState1.$verify();
mockState2.$verify();
assertEquals(
'Second undo must cause before action to dispatch', 2, beforeUndoCount);
// Test last undo.
mockState2.$reset();
mockState2.undo();
mockState2.$replay();
manager.undo();
mockState2.$verify();
assertEquals(
'Third undo must cause before action to dispatch', 3, beforeUndoCount);
}
function testRedo() {
addStatesToManager();
manager.undo();
manager.undo();
manager.undo();
resetStates();
stateChangeCount = 0;
mockState1.redo();
mockState1.$replay();
manager.redo();
assertEquals(
'Pushing first item onto undo stack during redo must dispatch ' +
'state change.',
1, stateChangeCount);
assertEquals(
'First redo must cause before action to dispatch', 1, beforeRedoCount);
mockState1.$verify();
preventDefault = true;
mockState2.$replay();
manager.redo();
assertEquals(
'No stack transitions between 0 and 1, must not dispatch ' +
'state change.',
1, stateChangeCount);
assertEquals(
'Second redo must cause before action to dispatch', 2, beforeRedoCount);
mockState2.$verify(); // Verify that redo was prevented.
preventDefault = false;
mockState3.redo();
mockState3.$replay();
manager.redo();
assertEquals(
'Removing last item from redo stack must dispatch state change.', 2,
stateChangeCount);
assertEquals(
'Third redo must cause before action to dispatch', 3, beforeRedoCount);
mockState3.$verify();
mockState3.$reset();
mockState3.undo();
mockState3.$replay();
manager.undo();
assertEquals(
'Putting item on redo stack must dispatch state change.', 3,
stateChangeCount);
assertEquals('Undo must cause before action to dispatch', 4, beforeUndoCount);
mockState3.$verify();
}
function testRedo_Asynchronous() {
var stubState = new goog.editor.plugins.UndoRedoState(true);
var redoCalled = false;
stubState.redo = function() { redoCalled = true; };
stubState.undo = goog.nullFunction;
stubState.equals = function() { return false; };
manager.addState(stubState);
manager.addState(mockState1);
manager.addState(mockState2);
manager.undo();
manager.undo();
manager.undo();
stubState.dispatchEvent(goog.editor.plugins.UndoRedoState.ACTION_COMPLETED);
resetStates();
manager.redo();
assertTrue('redoCalled must be true (redo must be called).', redoCalled);
// Calling redo shouldn't actually redo since the first async redo hasn't
// fired an event yet.
mockState1.$replay();
manager.redo();
mockState1.$verify();
// Dispatching redo completed on first redo, should cause the second pending
// redo to happen.
mockState1.$reset();
mockState1.redo();
mockState1.$replay();
mockState2.$replay(); // Nothing should happen to mockState1.
stubState.dispatchEvent(goog.editor.plugins.UndoRedoState.ACTION_COMPLETED);
mockState1.$verify();
mockState2.$verify();
// Test last redo.
mockState2.$reset();
mockState2.redo();
mockState2.$replay();
manager.redo();
mockState2.$verify();
}
function testUndoAndRedoPeek() {
addStatesToManager();
manager.undo();
assertEquals(
'redoPeek must return the top of the redo stack.',
manager.redoStack_[manager.redoStack_.length - 1], manager.redoPeek());
assertEquals(
'undoPeek must return the top of the undo stack.',
manager.undoStack_[manager.undoStack_.length - 1], manager.undoPeek());
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy