/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.commands;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.whole.lang.iterators.IEntityIterator;
import org.whole.lang.iterators.IteratorFactory;
import org.whole.lang.lifecycle.IHistoryManager;
import org.whole.lang.matchers.Matcher;
import org.whole.lang.model.IEntity;
import org.whole.lang.model.InternalIEntity;
import org.whole.lang.models.codebase.XmlModel;
import org.whole.lang.models.factories.ModelsEntityFactory;
import org.whole.lang.models.model.Model;
import org.whole.lang.models.model.SimpleEntity;
import org.whole.lang.reflect.ReflectionFactory;
import org.whole.lang.util.EntityUtils;
import org.whole.test.SlowTests;
public class HistoryInvariantsTest {
Model model;
IHistoryManager history;
@BeforeClass
public static void deployWholePlatform() {
ReflectionFactory.deployWholePlatform();
}
@Before
public void setUp() throws Exception {
model = new XmlModel().create();
history = ReflectionFactory.getHistoryManager(model);
history.setHistoryEnabled(true);
}
private void performChanges(Model model) {
model.getName().setValue("my new model name");
model.getDeclarations().wRemove(0);
SimpleEntity se = ModelsEntityFactory.instance.createSimpleEntity();
model.getDeclarations().wAdd(se);
se.getName().setValue("my new simple name");
}
private SimpleEntity createSimpleEntity() {
SimpleEntity se = ModelsEntityFactory.instance.createSimpleEntity();
ReflectionFactory.getHistoryManager(se).setHistoryEnabled(true);
se.getName().setValue("my new simple name");
se.getTypes().wAdd(ModelsEntityFactory.instance.createSimpleName("T1"));
se.getFeatures().wAdd(ModelsEntityFactory.instance.createFeature());
return se;
}
@Test
public void testSameHistory() {
performChanges(model);
Assert.assertNotSame(history, ReflectionFactory.getHistoryManager(model));
Assert.assertTrue(history.equals(ReflectionFactory.getHistoryManager(model)));
}
@Test
public void testMergeHistory() {
performChanges(model);
int size1 = history.getUndoSize();
SimpleEntity se = createSimpleEntity();
Assert.assertEquals(size1, history.getUndoSize());
model.getDeclarations().wAdd(se);
Assert.assertEquals(size1+1, history.getUndoSize());
size1 = history.getUndoSize();
se = createSimpleEntity();
se.wGetModel().getCompoundModel().setHistoryManager(history, false);
Assert.assertEquals(size1, history.getUndoSize());
model.getDeclarations().wAdd(se);
Assert.assertEquals(size1+1, history.getUndoSize());
size1 = history.getUndoSize();
se = createSimpleEntity();
se.wGetModel().getCompoundModel().setHistoryManager(history, true);
Assert.assertEquals(size1+1, history.getUndoSize());
model.getDeclarations().wAdd(se);
Assert.assertEquals(size1+2, history.getUndoSize());
size1 = history.getUndoSize();
se = createSimpleEntity();
history.mergeHistory(ReflectionFactory.getHistoryManager(se));
Assert.assertEquals(size1+1, history.getUndoSize());
model.getDeclarations().wAdd(se);
Assert.assertEquals(size1+2, history.getUndoSize());
}
@Test
public void testHistoryDefaultHistoryEnablement() {
IEntity model = new XmlModel().create();
IHistoryManager history = ReflectionFactory.getHistoryManager(model);
Assert.assertFalse(history.isHistoryEnabled());
Assert.assertEquals(0, history.getUndoSize());
Assert.assertTrue(history.getUndoCommands().isEmpty());
}
@Test
public void testModelNullCommands() {
IEntityIterator<IEntity> i = IteratorFactory.descendantOrSelfIterator();
i.reset(model);
for (IEntity e : i) {
Assert.assertEquals(NullCommand.instance, ((InternalIEntity) e).wGetBindingCommand());
Assert.assertEquals(NullCommand.instance, ((InternalIEntity) e).wGetLastCommand());
}
}
@Test
public void testAscendingChangeIndex() {
performChanges(model);
List<ICommand> changes = history.getUndoCommands();
int prevTime = 0;
for (int i=0; i<changes.size(); i++) {
int execTime = changes.get(i).getExecutionTime();
Assert.assertTrue(prevTime <= execTime);
prevTime = execTime;
}
}
@Test
public void testModelCommands() {
IEntityIterator<IEntity> i = IteratorFactory.descendantOrSelfIterator();
i.reset(model);
for (IEntity e : i) {
ICommand cmd = ((InternalIEntity) e).wGetBindingCommand();
Assert.assertTrue(cmd.getKind() == CommandKind.NULL);
cmd = ((InternalIEntity) e).wGetLastCommand();
Assert.assertTrue(cmd.getKind() == CommandKind.NULL);
}
performChanges(model);
List<ICommand> changes = history.getUndoCommands();
i = IteratorFactory.descendantOrSelfIterator();
i.reset(model);
for (IEntity e : i) {
ICommand cmd = ((InternalIEntity) e).wGetBindingCommand();
if (cmd.getKind() != CommandKind.NULL)
Assert.assertTrue(changes.contains(cmd));
cmd = ((InternalIEntity) e).wGetLastCommand();
if (cmd.getKind() != CommandKind.NULL)
Assert.assertTrue(changes.contains(cmd));
}
}
@Category(SlowTests.class)
@Test
public void testModelCloneHistory() {
performChanges(model);
IEntity model2 = EntityUtils.clone(model);
IEntityIterator<IEntity> i = IteratorFactory.descendantOrSelfIterator();
i.reset(model2);
for (IEntity e : i) {
ICommand cmd = ((InternalIEntity) e).wGetBindingCommand();
Assert.assertTrue(cmd.getKind() == CommandKind.NULL);
cmd = ((InternalIEntity) e).wGetLastCommand();
if (cmd.getKind() != CommandKind.NULL)
Assert.assertTrue(cmd.getKind() == CommandKind.NULL);
}
Assert.assertTrue(Matcher.match(model2, model));
}
@Test
public void testClearHistory() {
performChanges(model);
IEntity model2 = EntityUtils.clone(model);
history.clearHistory();
Assert.assertTrue(history.getUndoCommands().isEmpty());
IEntityIterator<IEntity> i = IteratorFactory.descendantOrSelfIterator();
i.reset(model);
for (IEntity e : i) {
ICommand cmd = ((InternalIEntity) e).wGetBindingCommand();
Assert.assertTrue(cmd.getKind() == CommandKind.NULL);
cmd = ((InternalIEntity) e).wGetLastCommand();
Assert.assertTrue(cmd.getKind() == CommandKind.NULL);
}
Assert.assertTrue(Matcher.match(model2, model));
}
@Test
public void testTrimHistory() {
performChanges(model);
String oldValue = model.getName().getValue();
model.getName().setValue("new name");
Assert.assertTrue(history.getUndoSize() > 1);
history.trimHistory(1);
Assert.assertEquals(1, history.getUndoSize());
history.undo();
Assert.assertEquals(oldValue, model.getName().getValue());
Assert.assertEquals(0, history.getUndoSize());
}
@Test
public void testHistoryCapacity() {
performChanges(model);
model.getName().setValue("new name");
Assert.assertTrue(history.getUndoSize() > 2);
history.setHistoryCapacity(2);
Assert.assertEquals(2, history.getUndoSize());
performChanges(model);
model.getName().setValue("new name 3");
Assert.assertEquals(2, history.getUndoSize());
history.setHistoryCapacity(3);
Assert.assertEquals(2, history.getUndoSize());
model.getName().setValue("new name 4");
Assert.assertEquals(3, history.getUndoSize());
}
// The entity local history of binding commands is ordered
// invariant: for each cmd, cmd.prevCommand.executionTime <= cmd.executionTime
@Test
public void testPrevCommandExecutionTimeOrder() {
performChanges(model);
IEntityIterator<IEntity> i = IteratorFactory.descendantOrSelfIterator();
i.reset(model);
for (IEntity e : i) {
ICommand cmd = ((InternalIEntity) e).wGetBindingCommand();
while (cmd.getKind() != CommandKind.NULL) {
ICommand cmd1 = cmd.getPrevCommand();
Assert.assertTrue(cmd1.getExecutionTime() <= cmd.getExecutionTime());
cmd = cmd1;
}
}
}
@Test
public void testLastCommand() {
IEntity e1 = model.getName();
e1.wSetValue("newLangName");
ICommand c1 = ((InternalIEntity) e1).wGetLastCommand();
List<ICommand> changes = history.getUndoCommands();
ICommand lastCmd = (ICommand) changes.get(changes.size()-1);
Assert.assertSame(lastCmd, c1);
}
@Test
public void testChangeOrder() {
IEntity e1 = model.getName();
IEntity e2 = model.getNamespace();
e1.wSetValue("newLangName");
e2.wSetValue("newNamespace");
Assert.assertTrue(((InternalIEntity) e1).wGetLastCommand().getExecutionTime() <= ((InternalIEntity) e2).wGetLastCommand().getExecutionTime());
}
@Test
public void testUndo() {
InternalIEntity e1 = (InternalIEntity) model.getName();
e1.wSetValue("newLangName1");
ICommand c1 = e1.wGetLastCommand();
e1.wSetValue("newLangName2");
ICommand c2 = e1.wGetLastCommand();
e1.wSetValue("newLangName3");
Assert.assertNotSame(c1, e1.wGetLastCommand());
history.undo();
Assert.assertEquals(e1.wStringValue(), "newLangName2");
Assert.assertEquals(e1.wGetLastCommand(), c2);
history.undo();
Assert.assertEquals(e1.wStringValue(), "newLangName1");
Assert.assertEquals(e1.wGetLastCommand(), c1);
}
@Test
public void testUndoRedo() {
InternalIEntity e1 = (InternalIEntity) model.getName();
e1.wSetValue("newLangName1");
ICommand c1 = e1.wGetLastCommand();
e1.wSetValue("newLangName2");
ICommand c2 = e1.wGetLastCommand();
history.undo();
Assert.assertEquals(e1.wStringValue(), "newLangName1");
Assert.assertEquals(e1.wGetLastCommand(), c1);
history.redo();
Assert.assertEquals(e1.wStringValue(), "newLangName2");
Assert.assertEquals(e1.wGetLastCommand(), c2);
}
@Test
public void testUndoSet() {
InternalIEntity e1 = (InternalIEntity) model.getName();
e1.wSetValue("newLangName1");
ICommand c1 = e1.wGetLastCommand();
e1.wSetValue("newLangName2");
ICommand c2 = e1.wGetLastCommand();
Assert.assertNotSame(c2, c1);
history.undo();
e1.wSetValue("newLangName3");
Assert.assertSame(e1.wGetLastCommand().getPrevCommand(), c1);
}
@Test
public void testUndoRedoAll() {
IEntity model2 = EntityUtils.clone(model);
performChanges(model);
IEntity model3 = EntityUtils.clone(model);
while (history.getUndoSize() > 0)
history.undo();
Assert.assertTrue(history.getUndoCommands().isEmpty());
Assert.assertTrue(Matcher.match(model2, model));
while (history.getRedoSize() > 0)
history.redo();
Assert.assertTrue(history.getRedoCommands().isEmpty());
Assert.assertTrue(Matcher.match(model3, model));
}
}