/*
* Copyright 2017 Laszlo Balazs-Csiki
*
* This file is part of Pixelitor. Pixelitor is free software: you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License, version 3 as published by the Free
* Software Foundation.
*
* Pixelitor 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 Pixelitor. If not, see <http://www.gnu.org/licenses/>.
*/
package pixelitor;
import org.junit.Before;
import org.junit.Test;
import pixelitor.history.History;
import pixelitor.layers.ImageLayer;
import pixelitor.layers.Layer;
import java.awt.Rectangle;
import java.awt.Shape;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
public class CompositionTest {
private Composition comp;
private CompTester tester;
@Before
public void setUp() {
comp = TestHelper.create2LayerComposition(true);
assertEquals("Composition{name='Test', activeLayer=layer 2, layerList=[" +
"ImageLayer{state=NORMAL, super={tx=0, ty=0, super={name='layer 1', visible=true, " +
"mask=LayerMask{state=NORMAL, super={tx=0, ty=0, super={name='layer 1 MASK', visible=true, mask=null, maskEditing=false, maskEnabled=true, isAdjustment=false}}}, maskEditing=false, maskEnabled=true, isAdjustment=false}}}, " +
"ImageLayer{state=NORMAL, super={tx=0, ty=0, super={name='layer 2', visible=true, " +
"mask=LayerMask{state=NORMAL, super={tx=0, ty=0, super={name='layer 2 MASK', visible=true, mask=null, maskEditing=false, maskEnabled=true, isAdjustment=false}}}, maskEditing=false, maskEnabled=true, isAdjustment=false}}}], " +
"canvas=Canvas{width=20, height=10}, selection=null, dirty=false}", comp.toString());
tester = new CompTester(comp);
tester.checkDirty(false);
History.setUndoLevels(10);
History.clear();
}
@Test
public void testAddNewEmptyLayer() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.addNewEmptyLayer("newLayer 1", true);
tester.checkLayers("[layer 1, ACTIVE newLayer 1, layer 2]");
History.assertNumEditsIs(1);
History.assertLastEditNameIs("New Empty Layer");
comp.addNewEmptyLayer("newLayer 2", false);
tester.checkLayers("[layer 1, newLayer 1, ACTIVE newLayer 2, layer 2]");
tester.checkDirty(true);
History.assertNumEditsIs(2);
History.assertLastEditNameIs("New Empty Layer");
History.undo();
tester.checkLayers("[layer 1, ACTIVE newLayer 1, layer 2]");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
History.redo();
tester.checkLayers("[layer 1, ACTIVE newLayer 1, layer 2]");
History.redo();
tester.checkLayers("[layer 1, newLayer 1, ACTIVE newLayer 2, layer 2]");
}
@Test
public void testSetActiveLayer() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
Layer layer = comp.getLayer(0);
comp.setActiveLayer(layer, true);
assertSame(layer, comp.getActiveLayer());
tester.checkLayers("[ACTIVE layer 1, layer 2]");
tester.checkDirty(true);
History.assertNumEditsIs(1);
History.assertLastEditNameIs("Layer Selection Change");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
History.redo();
tester.checkLayers("[ACTIVE layer 1, layer 2]");
}
@Test
public void testAddLayerNoGUI() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
ImageLayer newLayer = TestHelper.createImageLayer("layer 3", comp);
comp.addLayerNoGUI(newLayer);
tester.checkLayers("[layer 1, layer 2, ACTIVE layer 3]");
tester.checkDirty(false);
}
@Test
public void testAddLayer() {
// add bellow active
comp.addLayer(TestHelper.createImageLayer("layer A", comp),
true, "New Test Layer", true, true);
tester.checkLayers("[layer 1, ACTIVE layer A, layer 2]");
tester.checkDirty(true);
// add above active
comp.addLayer(TestHelper.createImageLayer("layer B", comp),
true, "New Test Layer", true, false);
tester.checkLayers("[layer 1, layer A, ACTIVE layer B, layer 2]");
// add to position 0
comp.addLayer(TestHelper.createImageLayer("layer C", comp),
true, "New Test Layer", true, 0);
tester.checkLayers("[ACTIVE layer C, layer 1, layer A, layer B, layer 2]");
// add to position 2
comp.addLayer(TestHelper.createImageLayer("layer D", comp),
true, "New Test Layer", true, 2);
tester.checkLayers("[layer C, layer 1, ACTIVE layer D, layer A, layer B, layer 2]");
History.assertNumEditsIs(4);
History.assertLastEditNameIs("New Test Layer");
History.undo();
tester.checkLayers("[ACTIVE layer C, layer 1, layer A, layer B, layer 2]");
History.undo();
tester.checkLayers("[layer 1, layer A, ACTIVE layer B, layer 2]");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer A, layer 2]");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
History.redo();
tester.checkLayers("[layer 1, ACTIVE layer A, layer 2]");
History.redo();
tester.checkLayers("[layer 1, layer A, ACTIVE layer B, layer 2]");
History.redo();
tester.checkLayers("[ACTIVE layer C, layer 1, layer A, layer B, layer 2]");
History.redo();
tester.checkLayers("[layer C, layer 1, ACTIVE layer D, layer A, layer B, layer 2]");
}
@Test
public void testDuplicateLayer() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.duplicateActiveLayer();
tester.checkLayers("[layer 1, layer 2, ACTIVE layer 2 copy]");
tester.checkDirty(true);
History.assertNumEditsIs(1);
History.assertLastEditNameIs("Duplicate Layer");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
History.redo();
tester.checkLayers("[layer 1, layer 2, ACTIVE layer 2 copy]");
}
@Test
public void testGetCanvas() {
Canvas canvas = comp.getCanvas();
assertThat(canvas).isNotNull();
assertThat(canvas.toString()).isEqualTo("Canvas{width=20, height=10}");
comp.checkInvariant();
}
@Test
public void testIsEmpty() {
boolean empty = comp.isEmpty();
assertThat(empty).isFalse();
comp.checkInvariant();
}
@Test
public void testTranslationWODuplicating() {
testTranslation(false);
}
@Test
public void testTranslationWithDuplicating() {
testTranslation(true);
}
@Test
public void testFlattenImage() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.flattenImage(false);
tester.checkLayers("[ACTIVE flattened]");
tester.checkDirty(true);
// there is no undo for flatten image
}
@Test
public void testMergeDown() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.setActiveLayer(comp.getLayer(1), true);
comp.mergeDown(false);
tester.checkLayers("[ACTIVE layer 1]");
tester.checkDirty(true);
History.assertNumEditsIs(1);
History.assertLastEditNameIs("Merge Down");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
History.redo();
tester.checkLayers("[ACTIVE layer 1]");
}
@Test
public void testMoveActiveLayer() {
tester.checkDirty(false);
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.moveActiveLayerUp();
tester.checkDirty(false);
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.moveActiveLayerDown();
tester.checkDirty(true);
tester.checkLayers("[ACTIVE layer 2, layer 1]");
comp.moveActiveLayerUp();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.moveActiveLayerToBottom();
tester.checkLayers("[ACTIVE layer 2, layer 1]");
comp.moveActiveLayerToTop();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.swapLayers(0, 1, true);
tester.checkLayers("[ACTIVE layer 2, layer 1]");
}
@Test
public void testMoveLayerSelection() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.moveLayerSelectionDown();
tester.checkLayers("[ACTIVE layer 1, layer 2]");
comp.moveLayerSelectionUp();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
tester.checkDirty(true);
}
@Test
public void testGenerateNewLayerName() {
String newLayerName = comp.generateNewLayerName();
assertThat(newLayerName).isEqualTo("layer 1");
comp.checkInvariant();
}
@Test
public void testGetCanvasBounds() {
Rectangle bounds = comp.getCanvasBounds();
assertThat(bounds).isNotNull();
assertThat(bounds.toString()).isEqualTo("java.awt.Rectangle[x=0,y=0,width=20,height=10]");
comp.checkInvariant();
}
@Test
public void testDeleteActiveLayer() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.deleteActiveLayer(false, true);
tester.checkLayers("[ACTIVE layer 1]");
tester.checkDirty(true);
History.assertNumEditsIs(1);
History.assertLastEditNameIs("Delete Layer");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
History.redo();
tester.checkLayers("[ACTIVE layer 1]");
}
@Test
public void testDeleteLayer() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
Layer layer2 = comp.getLayer(1);
comp.deleteLayer(layer2, true, false);
tester.checkLayers("[ACTIVE layer 1]");
tester.checkDirty(true);
History.assertNumEditsIs(1);
History.assertLastEditNameIs("Delete Layer");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
History.redo();
tester.checkLayers("[ACTIVE layer 1]");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
// now delete layer 1
Layer layer1 = comp.getLayer(0);
comp.setActiveLayer(layer1, true);
tester.checkLayers("[ACTIVE layer 1, layer 2]");
comp.deleteLayer(layer1, true, false);
tester.checkLayers("[ACTIVE layer 2]");
History.undo();
tester.checkLayers("[ACTIVE layer 1, layer 2]");
History.redo();
tester.checkLayers("[ACTIVE layer 2]");
}
@Test
public void testAddNewLayerFromComposite() {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
comp.addNewLayerFromComposite("composite layer");
tester.checkLayers("[layer 1, layer 2, ACTIVE composite layer]");
tester.checkDirty(true);
History.assertNumEditsIs(1);
History.assertLastEditNameIs("New Layer from Composite");
History.undo();
tester.checkLayers("[layer 1, ACTIVE layer 2]");
History.redo();
tester.checkLayers("[layer 1, layer 2, ACTIVE composite layer]");
}
@Test
public void testIsActiveLayer() {
Layer layer1 = comp.getLayer(0);
Layer layer2 = comp.getLayer(1);
assertThat(comp.isActiveLayer(layer1)).isFalse();
assertThat(comp.isActiveLayer(layer2)).isTrue();
comp.checkInvariant();
comp.setActiveLayer(layer1, true);
assertThat(comp.isActiveLayer(layer1)).isTrue();
assertThat(comp.isActiveLayer(layer2)).isFalse();
comp.checkInvariant();
}
@Test
public void testInvertSelection() {
comp.invertSelection();
comp.checkInvariant();
tester.addRectangleSelection(3, 3, 4, 4);
tester.checkSelectionBounds(new Rectangle(3, 3, 4, 4));
comp.invertSelection();
tester.checkSelectionBounds(comp.getCanvasBounds());
History.assertNumEditsIs(1);
History.assertLastEditNameIs("Invert Selection");
History.undo();
tester.checkSelectionBounds(new Rectangle(3, 3, 4, 4));
History.redo();
tester.checkSelectionBounds(comp.getCanvasBounds());
}
@Test
public void testCreateSelectionFromShape() {
comp.createSelectionFromShape(new Rectangle(3, 3, 5, 5));
comp.checkInvariant();
Shape shape = comp.getSelection().getShape();
assertThat(shape).isEqualTo(new Rectangle(3, 3, 5, 5));
}
@Test
public void testDragFinished() {
Layer layer = comp.getLayer(0);
comp.dragFinished(layer, 1);
comp.checkInvariant();
}
private void testTranslation(boolean makeDuplicateLayer) {
tester.checkLayers("[layer 1, ACTIVE layer 2]");
// delete one layer so that we have undo
comp.deleteLayer(comp.getActiveLayer(), true, false);
tester.checkLayers("[ACTIVE layer 1]");
History.assertNumEditsIs(1);
tester.checkActiveLayerTranslation(0, 0);
tester.checkActiveLayerAndMaskImageSize(20, 10);
// 1. direction south-east
tester.moveLayer(makeDuplicateLayer, 2, 2);
tester.checkDirty(true);
// no translation because the image was moved south-east, and enlarged
tester.checkActiveLayerTranslation(0, 0);
tester.checkActiveLayerAndMaskImageSize(22, 12);
History.assertNumEditsIs(makeDuplicateLayer ? 3 : 2);
History.assertLastEditNameIs("Move Layer");
if (makeDuplicateLayer) {
tester.checkLayers("[layer 1, ACTIVE layer 1 copy]");
} else {
// no change in the number of layers
tester.checkLayers("[ACTIVE layer 1]");
History.assertNumEditsIs(2);
}
// 2. direction north-west
tester.moveLayer(makeDuplicateLayer, -2, -2);
// this time we have a non-zero translation
tester.checkActiveLayerTranslation(-2, -2);
// no need to enlarge the image again
tester.checkActiveLayerAndMaskImageSize(22, 12);
if (!makeDuplicateLayer) {
History.assertNumEditsIs(3);
}
// 3. direction north-west again
tester.moveLayer(makeDuplicateLayer, -2, -2);
// the translation increases
tester.checkActiveLayerTranslation(-4, -4);
// the image needs to be enlarged now
tester.checkActiveLayerAndMaskImageSize(24, 14);
if (!makeDuplicateLayer) {
History.assertNumEditsIs(4);
}
// 4. direction north-east
tester.moveLayer(makeDuplicateLayer, 2, -2);
// the translation increases
tester.checkActiveLayerTranslation(-2, -6);
// the image needs to be enlarged vertically
tester.checkActiveLayerAndMaskImageSize(24, 16);
if (!makeDuplicateLayer) {
History.assertNumEditsIs(5);
}
// 5. opposite movement: direction south-west
tester.moveLayer(makeDuplicateLayer, -2, 2);
// translation back to -4, -4
tester.checkActiveLayerTranslation(-4, -4);
// no need to enlarge the image
tester.checkActiveLayerAndMaskImageSize(24, 16);
if (!makeDuplicateLayer) {
History.assertNumEditsIs(6);
}
if (makeDuplicateLayer) {
tester.checkLayers("[layer 1, layer 1 copy, layer 1 copy 2, layer 1 copy 3, layer 1 copy 4, ACTIVE layer 1 copy 5]");
} else {
// no change in the number of layers
tester.checkLayers("[ACTIVE layer 1]");
}
if (!makeDuplicateLayer) { // we should have undo in this case
for (int i = 0; i < 6; i++) {
History.undo();
}
tester.checkActiveLayerTranslation(0, 0);
tester.checkActiveLayerAndMaskImageSize(20, 10);
for (int i = 0; i < 6; i++) {
History.redo();
}
tester.checkActiveLayerTranslation(-4, -4);
tester.checkActiveLayerAndMaskImageSize(24, 16);
}
// now test "Layer to Canvas Size"
comp.activeLayerToCanvasSize();
tester.checkActiveLayerTranslation(0, 0);
tester.checkActiveLayerAndMaskImageSize(20, 10);
History.undo();
tester.checkActiveLayerTranslation(-4, -4);
tester.checkActiveLayerAndMaskImageSize(24, 16);
History.redo();
tester.checkActiveLayerTranslation(0, 0);
tester.checkActiveLayerAndMaskImageSize(20, 10);
}
@Test
public void testDeselect() {
assertThat(comp.hasSelection()).isFalse();
tester.setStandardTestSelection();
assertThat(comp.hasSelection()).isTrue();
tester.checkSelectionBounds(tester.getStandardTestSelectionShape());
comp.deselect(true);
assertThat(comp.hasSelection()).isFalse();
History.assertNumEditsIs(1);
History.assertLastEditNameIs("Deselect");
History.undo();
assertThat(comp.hasSelection()).isTrue();
tester.checkSelectionBounds(tester.getStandardTestSelectionShape());
History.redo();
assertThat(comp.hasSelection()).isFalse();
}
@Test
public void testCropSelection() {
tester.setStandardTestSelection();
tester.checkSelectionBounds(tester.getStandardTestSelectionShape());
comp.cropSelection(new Rectangle(2, 2, 4, 4));
tester.checkSelectionBounds(new Rectangle(2, 2, 2, 2));
}
@Test
public void testSimpleMethods() {
assertThat(comp.getActiveLayerIndex()).isEqualTo(1);
assertThat(comp.activeIsDrawable()).isTrue();
assertThat(comp.getName()).isEqualTo("Test");
comp.setName("New Name");
assertThat(comp.getName()).isEqualTo("New Name");
}
}