1 // ==========================================================================
  2 // SC.UndoManager Unit Test
  3 // ==========================================================================
  4 /*globals SC */
  5 
  6 module("SC.UndoManager");
  7 
  8 test("simple undo case", function () {
  9   var undoManager = SC.UndoManager.create(),
 10     obj = SC.Object.create({
 11       undoManager: undoManager,
 12 
 13       value: null,
 14 
 15       actionName: 0,
 16 
 17       _undoAction: function(value) {
 18         this.set('value', value);
 19       },
 20 
 21       valDidChange: function() {
 22         var that = this,
 23           value = this._value;
 24 
 25         undoManager.registerUndoAction(this, this._undoAction, value, this.actionName);
 26 
 27         this._value = this.get('value');
 28       }.observes('value')
 29     });
 30 
 31   obj.actionName = 'group1';
 32   obj.set('value', 'a');
 33   ok(undoManager.get('canUndo'), "We should be able to undo");
 34   equals(undoManager.get('undoActionName'), 'group1', "The name of the undo stack should be 'group1'");
 35 
 36   obj.actionName = 'group2';
 37   obj.set('value', 'ab');
 38 
 39   obj.actionName = 'group3';
 40   obj.set('value', 'abc');
 41   equals(undoManager.get('undoActionName'), 'group3', "The name of the undo stack should be 'group3'");
 42 
 43   undoManager.undo();
 44   equals(obj.get('value'), 'ab', "val should be 'ab'");
 45   ok(undoManager.get('canRedo'), "We should be able to redo");
 46   equals(undoManager.get('undoActionName'), 'group2', "The name of the undo stack should be 'group2'");
 47   equals(undoManager.get('redoActionName'), 'group3', "The name of the redo stack should be 'group3'");
 48 
 49   undoManager.undo();
 50   equals(obj.get('value'), 'a', "val should be 'a'");
 51   equals(undoManager.get('undoActionName'), 'group1', "The name of the undo stack should be 'group1'");
 52   equals(undoManager.get('redoActionName'), 'group2', "The name of the redo stack should be 'group2'");
 53 
 54   undoManager.redo();
 55   equals(obj.get('value'), 'ab', "val should be 'ab'");
 56   equals(undoManager.get('undoActionName'), 'group2', "The name of the undo stack should be 'group2'");
 57   equals(undoManager.get('redoActionName'), 'group3', "The name of the redo stack should be 'group3'");
 58 
 59   undoManager.undo();
 60   equals(obj.get('value'), 'a', "val should be 'a'");
 61 
 62   undoManager.undo();
 63   equals(obj.get('value'), null, "val should be 'null'");
 64   ok(!undoManager.get('canUndo'), "We shouldn't be able to undo");
 65   equals(undoManager.get('undoActionName'), null, "The name of the undo stack should be 'null'");
 66 
 67   undoManager.redo();
 68   equals(obj.get('value'), 'a', "val should be 'a'");
 69 
 70   undoManager.redo();
 71   equals(obj.get('value'), 'ab', "val should be 'ab'");
 72 
 73   undoManager.redo();
 74   equals(obj.get('value'), 'abc', "val should be 'abc'");
 75   ok(!undoManager.get('canRedo'), "We shouldn't be able to redo");
 76 
 77   undoManager.undo();
 78   undoManager.undo();
 79   equals(obj.get('value'), 'a', "val should be 'a'");
 80 
 81   obj.set('value', 'ad');
 82   ok(!undoManager.get('canRedo'), "We shouldn't be able to redo");
 83 
 84   undoManager.undo();
 85   ok(undoManager.get('canUndo'), "We should be able to undo");
 86   ok(undoManager.get('canRedo'), "We should be able to redo");
 87 
 88   undoManager.reset();
 89 
 90   ok(!undoManager.get('canUndo'), "We shouldn't be able to undo");
 91   ok(!undoManager.get('canRedo'), "We shouldn't be able to redo");
 92 });
 93 
 94 
 95 test("grouped undo case", function () {
 96   var undoManager = SC.UndoManager.create(),
 97     obj = SC.Object.create({
 98       undoManager: undoManager,
 99 
100       value: null,
101 
102       actionName: 0,
103 
104       _undoAction: function(value) {
105         this.set('value', value)
106       },
107 
108       valDidChange: function() {
109         var value = this._value,
110             actionName = this.actionName;
111 
112         if (actionName === this._actionName) {
113           undoManager.registerGroupedUndoAction(this, this._undoAction, value);
114         }
115         else {
116           undoManager.registerUndoAction(this, this._undoAction, value, actionName);
117         }
118 
119         this._value = this.get('value');
120         this._actionName = actionName;
121       }.observes('value')
122     });
123 
124   obj.actionName = 'group1';
125   obj.set('value', 'a');
126   ok(undoManager.get('canUndo'), "We should be able to undo");
127   equals(undoManager.get('undoActionName'), 'group1', "The name of the undo stack should be 'group1'");
128 
129   obj.actionName = 'group2';
130   obj.set('value', 'ab');
131   obj.set('value', 'abc');
132   equals(undoManager.get('undoActionName'), 'group2', "The name of the undo stack should be 'group2'");
133 
134   obj.actionName = 'group3';
135   obj.set('value', 'abcd');
136 
137   undoManager.undo();
138   equals(obj.get('value'), 'abc', "val should be 'abc'");
139   ok(undoManager.get('canRedo'), "We should be able to redo");
140   equals(undoManager.get('undoActionName'), 'group2', "The name of the undo stack should be 'group2'");
141   equals(undoManager.get('redoActionName'), 'group3', "The name of the redo stack should be 'group3'");
142 
143   undoManager.undo();
144   equals(obj.get('value'), 'a', "val should be 'a'");
145 
146   undoManager.redo();
147   equals(obj.get('value'), 'abc', "val should be 'abc'");
148 
149   undoManager.undo();
150   equals(obj.get('value'), 'a', "val should be 'a'");
151 
152   undoManager.undo();
153   equals(obj.get('value'), null, "val should be 'null'");
154   ok(!undoManager.get('canUndo'), "We shouldn't be able to undo");
155 
156   undoManager.redo();
157   equals(obj.get('value'), 'a', "val should be 'a'");
158 
159   undoManager.redo();
160   equals(obj.get('value'), 'abc', "val should be 'abc'");
161 
162   undoManager.redo();
163   equals(obj.get('value'), 'abcd', "val should be 'abcd'");
164   ok(!undoManager.get('canRedo'), "We shouldn't be able to redo");
165 
166   undoManager.redo();
167 });
168 
169 test("set action name", function () {
170   var undoManager = SC.UndoManager.create();
171 
172   undoManager.setActionName('group1');
173   undoManager.registerUndoAction();
174 
175   equals(undoManager.get('undoActionName'), null, "The name of the undo stack should be null");
176 
177   undoManager.setActionName('group1');
178 
179   equals(undoManager.get('undoActionName'), 'group1', "The name of the undo stack should be 'group1'");
180 });
181 
182 test("restrict number of groups", function () {
183   var undoManager = SC.UndoManager.create({
184       maxStackLength: 2
185     }),
186     obj = SC.Object.create({
187       undoManager: undoManager,
188       value: 0,
189       _undoAction: function(value) {
190         this.set('value', value);
191       },
192       valDidChange: function() {
193         var value = this.get('value') - 1;
194         undoManager.registerUndoAction(this, this._undoAction, value);
195       }.observes('value')
196     }),
197     computeStackLength = function(stack) {
198       var length = 1;
199       while(stack = stack.prev) {
200         length++;
201       }
202       return length;
203     },
204     length;
205 
206   obj.incrementProperty('value');
207   obj.incrementProperty('value');
208   obj.incrementProperty('value');
209   obj.incrementProperty('value');
210   obj.incrementProperty('value');
211 
212   equals(obj.get('value'), 5, "value should be 5");
213 
214   length = computeStackLength(undoManager.undoStack);
215   equals(length, 3, "The undo stack length should be 3");
216 
217   undoManager.endUndoGroup();
218 
219   length = computeStackLength(undoManager.undoStack);
220   equals(length, 2, "The undo stack length should be 2");
221 
222   undoManager.undo();
223   undoManager.undo();
224 
225   ok(!undoManager.get('canUndo'), "We shouldn't be able to undo");
226 
227   length = computeStackLength(undoManager.redoStack);
228   equals(length, 2, "The redo stack length should be 2");
229 });
230 
231 
232