org.photovault.imginfo.Test_PhotoInfo.java Source code

Java tutorial

Introduction

Here is the source code for org.photovault.imginfo.Test_PhotoInfo.java

Source

/*
  Copyright (c) 2006 Harri Kaimio
      
  This file is part of Photovault.
    
  Photovault 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 2 of the License, or
  (at your option) any later version.
    
  Photovault 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 Photovault; if not, write to the Free Software Foundation,
  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

package org.photovault.imginfo;

import java.awt.geom.Rectangle2D;
import java.io.*;
import java.util.*;
import java.sql.*;
import java.awt.image.*;
import javax.imageio.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.photovault.command.CommandException;
import org.photovault.command.CommandHandler;
import org.photovault.command.PhotovaultCommandHandler;
import org.photovault.common.PhotovaultException;
import org.photovault.dcraw.RawConversionSettings;
import org.photovault.persistence.DAOFactory;
import org.photovault.persistence.HibernateDAOFactory;
import org.photovault.persistence.HibernateUtil;
import org.photovault.replication.HibernateDtoResolverFactory;
import org.photovault.replication.VersionedObjectEditor;
import org.photovault.test.PhotovaultTestCase;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.*;

public class Test_PhotoInfo extends PhotovaultTestCase {
    static Log log = LogFactory.getLog(Test_PhotoInfo.class.getName());

    File testImgDir = new File(System.getProperty("basedir"), "testfiles");
    String nonExistingDir = "/tmp/_dirThatDoNotExist";
    Session session = null;
    Transaction tx = null;

    DAOFactory daoFactory;
    PhotoInfoDAO photoDAO;

    /**
     * Default constructor to set up OJB environment
     */
    public Test_PhotoInfo() {
        super();
    }

    /**
     Sets ut the test environment
     */
    @BeforeMethod
    public void setUp() {
        session = HibernateUtil.getSessionFactory().openSession();
        HibernateDAOFactory hdf = (HibernateDAOFactory) DAOFactory.instance(HibernateDAOFactory.class);
        hdf.setSession(session);
        daoFactory = hdf;
        photoDAO = daoFactory.getPhotoInfoDAO();
        tx = session.beginTransaction();
    }

    /**
     Tears down the testing environment
     */
    @AfterMethod
    public void tearDown() {
        tx.commit();
        session.close();
    }

    //    File testRefImageDir = new File( "c:\\java\\photovault\\tests\\images\\photovault\\imginfo" );
    File testRefImageDir = new File("tests/images/photovault/imginfo");

    /**
       Test case that verifies that an existing photo infor record 
       can be loaded successfully
    */
    @Test
    public void testRetrievalSuccess() throws InstantiationException, IllegalAccessException {
        UUID photoId = UUID.fromString("f5d73748-0fb4-40ab-bd05-d3740fb30783");
        HibernateDtoResolverFactory rf = new HibernateDtoResolverFactory(session);
        VersionedObjectEditor<PhotoInfo> pe = new VersionedObjectEditor(PhotoInfo.class, photoId, rf);
        photoDAO.makePersistent(pe.getTarget());
        session.flush();
        session.clear();

        PhotoInfo photo = null;
        photo = photoDAO.findByUUID(photoId);
        assertNotNull(photo);
        PhotoInfo photo2 = photoDAO.findByUUID(UUID.randomUUID());
        assertNull(photo2);
    }

    /** 
    Test updating object to DB
    */
    @Test
    public void testUpdate() {
        UUID photoId = UUID.fromString("f5d73748-0fb4-40ab-bd05-d3740fb30783");
        PhotoInfo photo = null;
        photo = photoDAO.findByUUID(photoId);
        assertTrue(photo != null);

        // Update the photo
        String shootingPlace = photo.getShootingPlace();
        String newShootingPlace = "Testipaikka";
        photo.setShootingPlace(newShootingPlace);
        photoDAO.flush();
        assertMatchesDb(photo);
    }

    /** 
    Test updating object to DB when shooting date has not been specified
    */
    @Test
    public void testNullShootDateUpdate() {
        UUID photoId = UUID.fromString("f5d73748-0fb4-40ab-bd05-d3740fb30783");
        PhotoInfo photo = null;
        photo = photoDAO.findByUUID(photoId);
        assertTrue(photo != null);

        java.util.Date origTime = photo.getShootTime();
        // Update the photo
        photo.setShootTime(null);
        tx.commit();
        session.clear();

        // retrieve the updated photo from DB and chech that the
        // modification has been done
        tx = session.beginTransaction();
        photo = photoDAO.findByUUID(photoId);
        assertNull("Shooting time was supposedly set to null", photo.getShootTime());

        // restore the shooting place
        photo.setShootTime(origTime);
    }

    /**
       Test normal creation of a persistent PhotoInfo object
    */
    @Test
    public void testPhotoCreation() {

        PhotoInfo photo = PhotoInfo.create();
        try {
            session.save(photo);
        } catch (Throwable t) {
            fail(t.getMessage());
        }
        assertNotNull(photo);
        photo.setPhotographer("TESTIKUVAAJA");
        photo.setShootingPlace("TESTPLACE");
        photo.setShootTime(new java.util.Date());
        photo.setFStop(5.6);
        photo.setShutterSpeed(0.04);
        photo.setFocalLength(50);
        photo.setCamera("Canon FTb");
        photo.setFilm("Tri-X");
        photo.setFilmSpeed(400);
        photo.setLens("Canon FD 50mm/F1.4");
        photo.setCropBounds(new Rectangle2D.Double(0.1, 0.2, 0.5, 0.7));
        photo.setDescription(
                "This is a long test description that tries to verify that the description mechanism really works");
        //   photo.updateDB();
        tx.commit();
        session.clear();

        tx = session.beginTransaction();

        PhotoInfo photo2 = null;
        photo2 = photoDAO.findByUUID(photo.getUuid());

        assertEquals(photo.getPhotographer(), photo2.getPhotographer());
        assertEquals(photo.getShootingPlace(), photo2.getShootingPlace());
        // assertEquals( photo.getShootTime(), photo2.getShootTime() );
        assertEquals(photo.getDescription(), photo2.getDescription());
        assertEquals(photo.getCamera(), photo2.getCamera());
        assertEquals(photo.getLens(), photo2.getLens());
        assertEquals(photo.getFilm(), photo2.getFilm());
        assertTrue(photo.getShutterSpeed() == photo2.getShutterSpeed());
        assertTrue(photo.getFilmSpeed() == photo2.getFilmSpeed());
        assertTrue(photo.getFocalLength() == photo2.getFocalLength());
        assertTrue(photo.getFStop() == photo2.getFStop());
        assertTrue(photo.getUuid().equals(photo2.getUuid()));
        assertTrue(photo.getCropBounds().equals(photo2.getCropBounds()));

        //       assertTrue( photo.equals( photo2 ));

    }

    /**
       Test normal creation of a persistent PhotoInfo object
    */
    @Test
    public void testChangeCommand() {
        PhotovaultCommandHandler cmdHandler = new PhotovaultCommandHandler(null);

        ChangePhotoInfoCommand photoCreateCmd = new ChangePhotoInfoCommand();
        try {
            cmdHandler.executeCommand(photoCreateCmd);
        } catch (CommandException ex) {
            fail(ex.getMessage());
        }
        Set<PhotoInfo> photos = photoCreateCmd.getChangedPhotos();
        assertEquals(1, photos.size());
        PhotoInfo photo = photos.toArray(new PhotoInfo[1])[0];

        photo = (PhotoInfo) session.merge(photo);

        assertNotNull(photo);

        ChangePhotoInfoCommand photoChangeCmd = new ChangePhotoInfoCommand(photo.getUuid());

        // photoChangeCmd.setUUID( UUID.randomUUID() );
        photoChangeCmd.setPhotographer("TESTIKUVAAJA");
        photoChangeCmd.setShootingPlace("TESTPLACE");
        // TODO: debug this!!!
        // photoChangeCmd.setShootTime( new java.util.Date() );
        photoChangeCmd.setFStop(5.6);
        photoChangeCmd.setShutterSpeed(0.04);
        photoChangeCmd.setFocalLength(50);
        photoChangeCmd.setCamera("Canon FTb");
        photoChangeCmd.setFilm("Tri-X");
        photoChangeCmd.setFilmSpeed(400);
        photoChangeCmd.setLens("Canon FD 50mm/F1.4");
        photoChangeCmd.setCropBounds(new Rectangle2D.Double(0.1, 0.2, 0.5, 0.7));
        photoChangeCmd.setDescription(
                "This is a long test description that tries to verify that the description mechanism really works");

        try {
            cmdHandler.executeCommand(photoChangeCmd);
        } catch (CommandException ex) {
            fail(ex.getMessage());
        }
        photos = photoChangeCmd.getChangedPhotos();
        assertEquals(1, photos.size());
        photo = photos.toArray(new PhotoInfo[1])[0];
        photo = (PhotoInfo) session.merge(photo);

        session.clear();

        PhotoInfo photo2 = null;
        photo2 = photoDAO.findByUUID(photo.getUuid());

        assertEquals(photo.getPhotographer(), photo2.getPhotographer());
        assertEquals(photo.getShootingPlace(), photo2.getShootingPlace());
        // assertEquals( photo.getShootTime(), photo2.getShootTime() );
        assertEquals(photo.getDescription(), photo2.getDescription());
        assertEquals(photo.getCamera(), photo2.getCamera());
        assertEquals(photo.getLens(), photo2.getLens());
        assertEquals(photo.getFilm(), photo2.getFilm());
        assertTrue(photo.getShutterSpeed() == photo2.getShutterSpeed());
        assertTrue(photo.getFilmSpeed() == photo2.getFilmSpeed());
        assertTrue(photo.getFocalLength() == photo2.getFocalLength());
        assertTrue(photo.getFStop() == photo2.getFStop());
        //        assertTrue( photo.getUid() == photo2.getUid() );
        assertTrue(photo.getUuid().equals(photo2.getUuid()));
        assertTrue(photo.getCropBounds().equals(photo2.getCropBounds()));

        //       assertTrue( photo.equals( photo2 ));
    }

    @Test
    public void testPhotoDeletion() {
        PhotoInfo photo = new PhotoInfo();
        session.save(photo);
        session.flush();

        // Check that the photo can be retrieved from DB

        Connection conn = session.connection();
        String sql = "SELECT * FROM photos WHERE photo_uuid = '" + photo.getUuid() + "'";
        Statement stmt = null;
        ResultSet rs = null;
        try {
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql);
            if (!rs.next()) {
                fail("Matching DB record not found");
            }
        } catch (SQLException e) {
            fail("DB error:; " + e.getMessage());
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (Exception e) {
                }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (Exception e) {
                }
            }
        }

        session.delete(photo);
        session.flush();
        // Check that the photo is deleted from the database
        try {
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql);
            if (rs.next()) {
                fail("Found matching DB record after delete");
            }
        } catch (SQLException e) {
            fail("DB error:; " + e.getMessage());
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (Exception e) {
                }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (Exception e) {
                }
            }
        }
    }

    @Test
    public void testCreationFromImage() {
        String fname = "test1.jpg";
        File f = new File(testImgDir, fname);
        PhotoInfo photo = createPhoto(f);
        assertNotNull(photo);
        OriginalImageDescriptor orig = photo.getOriginal();
        assertNotNull(orig);
        assertNull(orig.getFile().findAvailableCopy());
        ImageFile ifile = orig.getFile();
        orig.photos.remove(photo);
        photo.setOriginal(null);
        session.delete(photo);
    }

    /**
       Test that an exception is generated when trying to add
       nonexisting file to DB
    */
    @Test
    public void testfailedCreation() {
        String fname = "test1.jpg";
        File f = new File(nonExistingDir, fname);
        try {
            PhotoInfo photo = createPhoto(f);
            // Execution should never proceed this far since addToDB
            // should produce exception
            fail("Image file should have been nonexistent");
        } catch (Throwable e) {
            // This is what we except
        }
    }

    /**
       Test that creating a new thumbnail using createThumbnail works
     */
    @Test
    public void testThumbnailCreate() {
        String fname = "test1.jpg";
        File f = new File(testImgDir, fname);
        PhotoInfo photo = createPhoto(f);
        assertNotNull(photo);
        int copyCount = photo.getOriginal().getCopies().size();
        photo.createThumbnail();
        assertEquals("InstanceNum should be 1 greater after adding thumbnail", copyCount + 1,
                photo.getOriginal().getCopies().size());
        // Try to find the new thumbnail
        boolean foundThumbnail = false;
        CopyImageDescriptor thumbnail = (CopyImageDescriptor) photo.getPreferredImage(
                EnumSet.allOf(ImageOperations.class), EnumSet.allOf(ImageOperations.class), 0, 0, 100, 100);

        assertNotNull("Could not find the created thumbnail", thumbnail);
        assertEquals("Thumbnail width should be 100", 100, thumbnail.getWidth());
        File thumbnailFile = thumbnail.getFile().findAvailableCopy();
        assertTrue("Image file does not exist", thumbnailFile.exists());

        // Test the getThumbnail method
        Thumbnail thumb = photo.getThumbnail();
        assertNotNull(thumb);
        assertFalse("Thumbnail exists, should not return default thumbnail",
                thumb == Thumbnail.getDefaultThumbnail());

        session.flush();
        assertMatchesDb(photo);

        photo.delete();
        assertFalse("Image file does exist after delete", thumbnailFile.exists());
    }

    /**
       Tests thumbnail creation when there are no photo instances.
    */
    @Test
    public void testThumbnailCreateNoInstances() throws Exception {
        PhotoInfo photo = PhotoInfo.create();
        try {
            photo.createThumbnail();
            /*      
             TODO: Rewrite so that there is an original without any available locations
                   assertEquals( "Should not create a thumbnail instance when there are no original",
                       0, photo.getNumInstances() );
            */
        } catch (Exception e) {
            throw e;
        } finally {
            photo.delete();
        }
    }

    /**
       Tests thumbnail creation when the database is corrupted & files
       that photo instances refer to do not exist.
    */
    @Test
    public void testThumbnailCreateCorruptInstances() throws Exception {
        String fname = "test1.jpg";
        File f = new File(testImgDir, fname);
        PhotoInfo photo = createPhoto(f);

        // Corrupt the database by deleting the actual image files
        // that instances refer to
        for (FileLocation ifile : photo.getOriginal().getFile().getLocations()) {
            File file = ifile.getFile();
            file.delete();
        }

        // Create the thumbnail
        photo.createThumbnail();

        try {
            Thumbnail thumb = photo.getThumbnail();
            assertNotNull(thumb);
            assertTrue("Database is corrupt, should return error thumbnail",
                    thumb == Thumbnail.getErrorThumbnail());
            assertEquals("Database is corrupt, getThumbnail should not create a new instance", 1,
                    photo.getOriginal().getCopies().size());

        } finally {
            // Clean up in any case
            photo.delete();
        }
    }

    /**
       Test that creating a new thumbnail using getThumbnail works
     */
    @Test
    public void testGetThumbnail() {
        String fname = "test1.jpg";
        File f = new File(testImgDir, fname);
        PhotoInfo photo = createPhoto(f);

        assertNotNull(photo);
        Thumbnail thumb = photo.getThumbnail();
        assertNotNull(thumb);
        assertFalse("Thumbnail exists, should not return default thumbnail",
                thumb == Thumbnail.getDefaultThumbnail());

        // Try to find the new thumbnailTest_PhotoInfoChange
        boolean foundThumbnail = false;
        OriginalImageDescriptor orig = photo.getOriginal();

        CopyImageDescriptor thumbnail = null;
        for (CopyImageDescriptor copy : orig.getCopies()) {
            if (copy.getWidth() <= 100 && copy.getHeight() <= 100 && copy.getFile().findAvailableCopy() != null) {
                foundThumbnail = true;
                thumbnail = copy;
                break;
            }
        }
        assertTrue("Could not find the created thumbnail", foundThumbnail);
        assertEquals("Thumbnail width should be 100", 100, thumbnail.getWidth());
        File thumbnailFile = thumbnail.getFile().findAvailableCopy();
        assertTrue("Image file does not exist", thumbnailFile.exists());
        photo.delete();
        assertFalse("Image file does exist after delete", thumbnailFile.exists());
    }

    /**
       Test getThumbnail in situation where there is no image instances for the PhotoInfo
    */
    @Test
    public void testThumbWithNoInstances() {
        PhotoInfo photo = PhotoInfo.create();
        Thumbnail thumb = photo.getThumbnail();
        // TODO: Should getThumbnail really return defaultThumbnail in this situation?
        assertTrue("getThumbnail should return error thumbnail", thumb == Thumbnail.getErrorThumbnail());

        //   assertEquals( "No new instances should have been created", 0, photo.getNumInstances() );

        // Create a new instance and check that a valid thumbnail is returned after this
        File testFile = new File(testImgDir, "test1.jpg");
        if (!testFile.exists()) {
            fail("could not find test file " + testFile);
        }
        File instanceFile = VolumeBase.getDefaultVolume().getFilingFname(testFile);
        try {
            FileUtils.copyFile(testFile, instanceFile);
        } catch (IOException e) {
            fail(e.getMessage());
        }
        /*        
           photo.addInstance( VolumeBase.getDefaultVolume(), instanceFile, ImageInstance.INSTANCE_TYPE_ORIGINAL );
        */
        Thumbnail thumb2 = photo.getThumbnail();

        assertFalse("After instance addition, getThumbnail should not return default thumbnail", thumb == thumb2);
        assertEquals("There should be 1 copy", 1, photo.getOriginal().getCopies().size());

        photo.delete();

    }

    /**
       Test that thumbnail is rotated if prefRotation is nonzero
    */

    @Test
    public void testThumbnailRotation() {
        String fname = "test1.jpg";
        File f = new File(testImgDir, fname);
        PhotoInfo photo = createPhoto(f);
        photo.setPrefRotation(-45);

        Thumbnail thumb = photo.getThumbnail();

        // Compare thumbnail to the one saved
        File testFile = new File(testRefImageDir, "thumbnailRotation1.png");
        assertTrue("Thumbnail with 45 deg rotation does not match",
                org.photovault.test.ImgTestUtils.compareImgToFile(thumb.getImage(), testFile));

        photo.setPrefRotation(-90);
        thumb = photo.getThumbnail();
        testFile = new File(testRefImageDir, "thumbnailRotation2.png");
        assertTrue("Thumbnail with 90 deg rotation does not match",
                org.photovault.test.ImgTestUtils.compareImgToFile(thumb.getImage(), testFile));

        photo.delete();
    }

    /**
       PhotoInfoListener used for test cases
    */
    class TestListener implements PhotoInfoChangeListener {
        public boolean isNotified = false;

        public void photoInfoChanged(PhotoInfoChangeEvent e) {
            isNotified = true;
        }
    }

    /**
       Tests that the listener is working correctly
    */
    @Test
    public void testListener() {

        PhotoInfo photo = PhotoInfo.create();
        TestListener l1 = new TestListener();
        TestListener l2 = new TestListener();
        photo.addChangeListener(l1);
        photo.addChangeListener(l2);

        // Test that the listeners are notified
        photo.setPhotographer("TEST");
        assertTrue("l1 was not notified", l1.isNotified);
        assertTrue("l2 was not notified", l2.isNotified);

        // Test that the listeners are removed correctly
        photo.removeChangeListener(l2);
        l1.isNotified = false;
        l2.isNotified = false;
        photo.setPhotographer("TEST2");
        assertTrue("l1 was not notified", l1.isNotified);
        assertFalse("l2 was not supposed to be notified", l2.isNotified);

        // Test all object fields, one by one
        l1.isNotified = false;
        photo.setShootingPlace("TEST");
        assertTrue("no notification when changing shootingPlace", l1.isNotified);
        l1.isNotified = false;
        photo.setFStop(12);
        assertTrue("no notification when changing f-stop", l1.isNotified);
        l1.isNotified = false;
        photo.setFocalLength(10);
        assertTrue("no notification when changing focalLength", l1.isNotified);
        l1.isNotified = false;
        photo.setShootTime(new java.util.Date());
        assertTrue("no notification when changing shooting time", l1.isNotified);
        l1.isNotified = false;
        photo.setShutterSpeed(1.0);
        assertTrue("no notification when changing shutter speed", l1.isNotified);
        l1.isNotified = false;
        photo.setCamera("Leica");
        assertTrue("no notification when changing camera", l1.isNotified);
        l1.isNotified = false;
        photo.setLens("TESTLENS");
        assertTrue("no notification when changing lens", l1.isNotified);
        l1.isNotified = false;
        photo.setFilm("Pan-X");
        assertTrue("no notification when changing film", l1.isNotified);
        l1.isNotified = false;
        photo.setFilmSpeed(160);
        assertTrue("no notification when changing film speed", l1.isNotified);
        l1.isNotified = false;
        photo.setPrefRotation(107);
        assertTrue("no notification when changing preferred rotation", l1.isNotified);
        l1.isNotified = false;
        photo.setDescription("Test with lots of characters");
        assertTrue("no notification when changing description", l1.isNotified);
        photo.delete();
    }

    /**
       Test exporting an image to a file name that cannot be created
    */
    /*    public void testExportWriteNotAllowed() {
       fail ("Test case not implemented" );
        }
     */

    @Test
    public void testRawSettings() {
        PhotoInfo p = PhotoInfo.create();
        p = photoDAO.makePersistent(p);
        double chanMul[] = { 1., .7, .5, .7 };

        double daylightMul[] = { .3, .5, .7 };
        RawConversionSettings rs = RawConversionSettings.create(chanMul, daylightMul, 16000, 0, -.5, 0.,
                RawConversionSettings.WB_MANUAL, false);
        p.setRawSettings(rs);
        RawConversionSettings rs2 = p.getRawSettings();
        assertTrue(rs.equals(rs2));
        assertEquals(16000, rs2.getWhite());
        session.flush();
        assertMatchesDb(p);
        //        List l = session.createQuery( "from RawConversionSettings where rawSettingId = :id" ).
        //                setInteger( "id", p.getRawSettings().getRawSettingId() ).list();
        //        assertEquals( 1, l.size() );

    }

    @Test
    public void testPreferredImageSelection() throws CommandException {
        File f = new File(testImgDir, "test1.jpg");
        PhotoInfo photo = createPhoto(f);
        VolumeDAO volDAO = daoFactory.getVolumeDAO();
        File instanceFile = volDAO.getDefaultVolume().getFilingFname(f);
        try {
            FileUtils.copyFile(f, instanceFile);
        } catch (IOException e) {
            fail(e.getMessage());
        }
        ModifyImageFileCommand fileCmd = new ModifyImageFileCommand(photo.getOriginal().getFile());
        Volume vol = volDAO.getDefaultVolume();
        fileCmd.addLocation(vol.getFileLocation(instanceFile));
        cmdHandler.executeCommand(fileCmd);

        // Create a copy
        CreateCopyImageCommand copyCmd = new CreateCopyImageCommand(photo, vol, 200, 200);
        CreateCopyImageCommand copy2Cmd = new CreateCopyImageCommand(photo, vol, 100, 100);
        CreateCopyImageCommand copy3Cmd = new CreateCopyImageCommand(photo, vol, 300, 300);
        copy3Cmd.setOperationsToApply(EnumSet.of(ImageOperations.COLOR_MAP));

        cmdHandler.executeCommand(copyCmd);
        cmdHandler.executeCommand(copy2Cmd);
        cmdHandler.executeCommand(copy3Cmd);

        ImageDescriptorBase img = photo.getPreferredImage(EnumSet.allOf(ImageOperations.class),
                EnumSet.allOf(ImageOperations.class), 0, 0, 100, 100);
        assertEquals(100, img.getWidth());
        img = photo.getPreferredImage(EnumSet.allOf(ImageOperations.class), EnumSet.allOf(ImageOperations.class),
                150, 150, 300, 300);
        assertEquals(200, img.getWidth());

        photo.setPrefRotation(90);
        img = photo.getPreferredImage(EnumSet.allOf(ImageOperations.class), EnumSet.allOf(ImageOperations.class),
                150, 150, 300, 300);
        assertNull(img);

        img = photo.getPreferredImage(EnumSet.noneOf(ImageOperations.class), EnumSet.allOf(ImageOperations.class),
                201, 201, 300, 300);
        assertEquals(300, img.getWidth());

    }

    @Test
    public void testTagging() throws InstantiationException, IllegalAccessException {
        UUID photoId = UUID.randomUUID();
        HibernateDtoResolverFactory rf = new HibernateDtoResolverFactory(session);
        VersionedObjectEditor<PhotoInfo> pe = new VersionedObjectEditor(PhotoInfo.class, photoId, rf);
        photoDAO.makePersistent(pe.getTarget());
        session.flush();
        session.clear();
        PhotoInfo photo = null;
        photo = photoDAO.findByUUID(photoId);
        assertNotNull(photo);
        pe = new VersionedObjectEditor<PhotoInfo>(photo, rf);
        pe.addToSet("tags", new Tag("test1"));
        pe.addToSet("tags", new Tag("animals", "giraffe"));
        pe.apply();
        session.flush();
        session.clear();

        photo = photoDAO.findByUUID(photoId);
        assertNotNull(photo);
        assertEquals(2, photo.getTags().size());
        pe = new VersionedObjectEditor<PhotoInfo>(photo, rf);
        pe.removeFromSet("tags", new Tag("test1"));
        pe.apply();
        assertEquals(1, photo.getTags().size());

    }

    CommandHandler cmdHandler = new PhotovaultCommandHandler(null);

    PhotoInfo createPhoto(File f) {
        ModifyImageFileCommand cmd = new ModifyImageFileCommand(f);
        try {
            cmdHandler.executeCommand(cmd);
        } catch (CommandException ex) {
            fail(ex.getMessage());
        }
        return (PhotoInfo) session.merge(cmd.getCreatedPhotos().iterator().next());
    }

    /**
     Utility to check that the object in memory matches the DB
     */
    void assertMatchesDb(PhotoInfo p) {
        assertMatchesDb(p, session);
    }

}