/* * Copyright (c) 2008, SQL Power Group Inc. * * This file is part of Power*Architect. * * Power*Architect is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Power*Architect 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.object.undo; import java.beans.PropertyChangeEvent; import java.sql.Types; import java.util.ArrayList; import java.util.List; import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CompoundEdit; import javax.swing.undo.UndoableEdit; import junit.framework.TestCase; import ca.sqlpower.object.undo.SPObjectUndoManager; import ca.sqlpower.object.undo.SPObjectUndoManager.SPObjectUndoableEventAdapter; import ca.sqlpower.sqlobject.SQLColumn; import ca.sqlpower.sqlobject.SQLDatabase; import ca.sqlpower.sqlobject.SQLObjectException; import ca.sqlpower.sqlobject.SQLObjectRoot; import ca.sqlpower.sqlobject.SQLRelationship; import ca.sqlpower.sqlobject.SQLTable; import ca.sqlpower.sqlobject.StubSQLObject; import ca.sqlpower.sqlobject.SQLIndex.AscendDescend; import ca.sqlpower.util.TransactionEvent; public class TestUndoManager extends TestCase { /** * Helps test undo manager by logging all calls to setFoo() in the * history list. */ public class UndoTester extends StubSQLObject { public List<Integer> history = new ArrayList<Integer>(); public void setFoo(Integer v) { history.add(v); } } SPObjectUndoManager undoManager; SQLTable fkTable; SQLTable pkTable; protected void setUp() throws Exception { super.setUp(); System.out.println("-----------------Start setup for "+getName()+"----------------"); SQLObjectRoot root = new SQLObjectRoot(); SQLDatabase db = new SQLDatabase(); fkTable = new SQLTable(db,true); fkTable.setName("child"); root.addChild(fkTable); pkTable = new SQLTable(db,true); pkTable.setName("parent"); root.addChild(pkTable); undoManager = new SPObjectUndoManager(root); pkTable.begin("Setting up test"); pkTable.addColumn(new SQLColumn()); pkTable.addColumn(new SQLColumn()); pkTable.getPrimaryKeyIndex().addIndexColumn(pkTable.getColumn(0), AscendDescend.UNSPECIFIED); pkTable.getColumn(0).setName("pk1"); pkTable.getColumn(0).setType(Types.INTEGER); pkTable.getPrimaryKeyIndex().addIndexColumn(pkTable.getColumn(1), AscendDescend.UNSPECIFIED); pkTable.getColumn(1).setName("pk2"); pkTable.getColumn(1).setType(Types.INTEGER); pkTable.commit(); db.addChild(pkTable); db.addChild(fkTable); System.out.println("-----------------End setup for "+getName()+"----------------"); } public void testAllowCompoundEdit() { UndoableEdit stubEdit1 = new AbstractUndoableEdit(); UndoableEdit stubEdit2 = new AbstractUndoableEdit(); UndoableEdit stubEdit3 = new AbstractUndoableEdit(); CompoundEdit ce = new CompoundEdit(); ce.addEdit(stubEdit1); ce.addEdit(stubEdit2); ce.addEdit(stubEdit3); ce.end(); undoManager.addEdit(ce); assertTrue(undoManager.canUndo()); } public void testNestedCompoundEdits() { pkTable.setName("old"); fkTable.setName("old"); pkTable.setRemarks("old"); fkTable.setRemarks("old"); undoManager.getEventAdapter().transactionStarted( TransactionEvent.createStartTransactionEvent(this, "Starting compoundedit")); pkTable.setName("one"); undoManager.getEventAdapter().transactionStarted( TransactionEvent.createStartTransactionEvent(this, "Starting nested compoundedit")); fkTable.setName("two"); undoManager.getEventAdapter().transactionEnded( TransactionEvent.createEndTransactionEvent(this)); pkTable.setRemarks("three"); undoManager.getEventAdapter().transactionEnded( TransactionEvent.createEndTransactionEvent(this)); fkTable.setRemarks("four"); assertEquals("one", pkTable.getName()); assertEquals("two", fkTable.getName()); assertEquals("three", pkTable.getRemarks()); assertEquals("four", fkTable.getRemarks()); undoManager.undo(); assertEquals("one", pkTable.getName()); assertEquals("two", fkTable.getName()); assertEquals("three", pkTable.getRemarks()); assertEquals("old", fkTable.getRemarks()); undoManager.undo(); assertEquals("old", pkTable.getName()); assertEquals("old", fkTable.getName()); assertEquals("old", pkTable.getRemarks()); assertEquals("old", fkTable.getRemarks()); } /** * Makes sure compound edits added through the sql object event adapter * are undone in order of most recent to least recent. */ public void testCompoundEditsUndoInCorrectOrder() { UndoTester myTester = new UndoTester(); SPObjectUndoableEventAdapter adapter = undoManager.getEventAdapter(); myTester.addSPListener(adapter); myTester.begin("Test Compound undo"); adapter.propertyChanged( new PropertyChangeEvent( myTester, "foo", 0, 1)); adapter.propertyChanged( new PropertyChangeEvent( myTester, "foo", 1, 2)); adapter.propertyChanged( new PropertyChangeEvent( myTester, "foo", 2, 3)); myTester.commit(); undoManager.undo(); // Ensure the compound undo happened last..first assertEquals(Integer.valueOf(2), myTester.history.get(0)); assertEquals(Integer.valueOf(1), myTester.history.get(1)); assertEquals(Integer.valueOf(0), myTester.history.get(2)); } /** Makes sure that the side effects of changing a PK column's attributes are not a separate undo step */ public void testUndoRelationshipPkAttributeChange() throws SQLObjectException { SQLRelationship.createRelationship(pkTable, fkTable, false); SQLColumn pk1 = pkTable.getColumnByName("pk1"); assertEquals("pk1 was already the new type.. makes testing silly", pk1.getType(), Types.INTEGER); SQLColumn fk1 = fkTable.getColumnByName("pk1"); assertNotNull("fk column not in fkTable", fk1); assertEquals("pk and fk must start out with same datatype", pk1.getType(), fk1.getType()); pk1.setType(Types.BINARY); assertEquals("fkTable not updated when the pktable was updated",Types.BINARY,fk1.getType()); undoManager.undo(); assertEquals("fk1 didn't go back to old type", Types.INTEGER, fk1.getType()); // this is the point of the test assertEquals("pk1 didn't go back to old type", Types.INTEGER, pk1.getType()); } /** * Test to ensure magic is respected when moving FK index columns from the * primary key which changes the relationship identifyingness. */ public void testUndoIndexMoveAndRelationChange() throws Exception { pkTable.moveAfterPK(pkTable.getColumn(1)); assertEquals(1, pkTable.getPkSize()); assertEquals(0, fkTable.getPkSize()); SQLRelationship relationship = SQLRelationship.createRelationship(pkTable, fkTable, true); assertEquals(1, fkTable.getPkSize()); assertTrue(relationship.isIdentifying()); pkTable.getParent().begin("Test"); relationship.setIdentifying(false); fkTable.moveAfterPK(fkTable.getColumn(0)); pkTable.getParent().commit(); assertEquals(0, fkTable.getPkSize()); undoManager.undo(); assertEquals(true, relationship.isIdentifying()); assertEquals(1, fkTable.getPkSize()); } }