/* * PhotoCreationTest.java 18 sept. 2010 * * Copyright (c) 2010 Emmanuel PUYBARET / eTeks <info@eteks.com>. All Rights Reserved. * * This program 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. * * This program 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.eteks.sweethome3d.junit; import java.awt.Component; import java.awt.Dialog; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.GregorianCalendar; import java.util.List; import java.util.TimeZone; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.JSlider; import javax.swing.JSpinner; import junit.extensions.abbot.ComponentTestFixture; import abbot.finder.AWTHierarchy; import abbot.finder.BasicFinder; import abbot.finder.ComponentNotFoundException; import abbot.finder.ComponentSearchException; import abbot.finder.MultipleComponentsFoundException; import abbot.finder.matchers.ClassMatcher; import abbot.tester.JComponentTester; import abbot.tester.JFileChooserTester; import abbot.tester.JSliderTester; import com.eteks.sweethome3d.io.DefaultUserPreferences; import com.eteks.sweethome3d.io.HomeFileRecorder; import com.eteks.sweethome3d.model.AspectRatio; import com.eteks.sweethome3d.model.Compass; import com.eteks.sweethome3d.model.Home; import com.eteks.sweethome3d.model.HomeApplication; import com.eteks.sweethome3d.model.HomeRecorder; import com.eteks.sweethome3d.model.RecorderException; import com.eteks.sweethome3d.model.UserPreferences; import com.eteks.sweethome3d.swing.FileContentManager; import com.eteks.sweethome3d.swing.HomePane; import com.eteks.sweethome3d.swing.PhotoPanel; import com.eteks.sweethome3d.swing.PhotoSizeAndQualityPanel; import com.eteks.sweethome3d.swing.SwingViewFactory; import com.eteks.sweethome3d.swing.VideoPanel; import com.eteks.sweethome3d.tools.OperatingSystem; import com.eteks.sweethome3d.viewcontroller.ContentManager; import com.eteks.sweethome3d.viewcontroller.HomeController; import com.eteks.sweethome3d.viewcontroller.View; /** * Tests photo creation dialog. * @author Emmanuel Puybaret */ public class PhotoCreationTest extends ComponentTestFixture { private UserPreferences preferences; private HomeController homeController; @Override protected void setUp() throws Exception { super.setUp(); this.preferences = new DefaultUserPreferences() { @Override public void write() throws RecorderException { } }; SwingViewFactory viewFactory = new SwingViewFactory(); HomeApplication application = new HomeApplication() { @Override public HomeRecorder getHomeRecorder() { return new HomeFileRecorder(); } @Override public UserPreferences getUserPreferences() { return preferences; } }; // Create a dummy controller to load a home test file HomeController controller = new HomeController(new Home(), application, viewFactory); String testFile = new File(PhotoCreationTest.class.getResource("resources/home1.sh3d").toURI()).getAbsolutePath(); controller.open(testFile); // Wait home is opened for (int i = 0; i < 100 && application.getHomes().size() == 0; i++) { Thread.sleep(100); } List<Home> homes = application.getHomes(); assertEquals("Application doesn't contain one home", 1, homes.size()); assertEquals("Test home wasn't opened", testFile, homes.get(0).getName()); ContentManager contentManager = new FileContentManager(preferences) { @Override public String showSaveDialog(View parentView, String dialogTitle, ContentType contentType, String name) { String os = System.getProperty("os.name"); if (OperatingSystem.isMacOSX()) { // Let's pretend the OS isn't Mac OS X to get a JFileChooser instance that works better in test System.setProperty("os.name", "dummy"); } try { return super.showSaveDialog(parentView, dialogTitle, contentType, name); } finally { System.setProperty("os.name", os); } } }; this.homeController = new HomeController(homes.get(0), application, viewFactory, contentManager); } public void testSunLocation() { // Tests azimuth and elevation values computed in Compass to avoid any regression Compass compass = new Compass(0, 0, 2); compass.setLatitude((float)Math.toRadians(45)); compass.setLongitude((float)Math.toRadians(0)); compass.setTimeZone("Europe/Paris"); GregorianCalendar calendar = new GregorianCalendar(2010, GregorianCalendar.SEPTEMBER, 1, 14, 30, 10); calendar.setTimeZone(TimeZone.getTimeZone(compass.getTimeZone())); TestUtilities.assertEqualsWithinEpsilon("Incorrect azimuth", 3.383972f, compass.getSunAzimuth(calendar.getTimeInMillis()), 1E-5f); TestUtilities.assertEqualsWithinEpsilon("Incorrect elevation", 0.915943f, compass.getSunElevation(calendar.getTimeInMillis()), 1E-5f); compass = new Compass(0, 0, 2); compass.setLatitude((float)Math.toRadians(40)); compass.setLongitude((float)Math.toRadians(160)); compass.setTimeZone("Asia/Tokyo"); calendar = new GregorianCalendar(2011, GregorianCalendar.JANUARY, 31, 8, 0, 0); calendar.setTimeZone(TimeZone.getTimeZone(compass.getTimeZone())); TestUtilities.assertEqualsWithinEpsilon("Incorrect azimuth", 2.44565f, compass.getSunAzimuth(calendar.getTimeInMillis()), 1E-5f); TestUtilities.assertEqualsWithinEpsilon("Incorrect elevation", 0.38735f, compass.getSunElevation(calendar.getTimeInMillis()), 1E-5f); } public void testPhotoCreation() throws InterruptedException, ComponentSearchException, NoSuchFieldException, IllegalAccessException, InvocationTargetException, IOException { final JComponent view = (JComponent)this.homeController.getView(); // Create a frame that displays a home view JFrame frame = new JFrame("Photo Creation Test"); frame.add(view); frame.pack(); showWindow(frame); JComponentTester tester = new JComponentTester(); tester.waitForIdle(); JDialog photoCreationDialog = showPhotoCreationPanel(this.preferences, this.homeController, frame, tester); // Retrieve PhotoPanel components PhotoPanel panel = (PhotoPanel)TestUtilities.findComponent(photoCreationDialog, PhotoPanel.class); JButton createButton = (JButton)TestUtilities.getField(panel, "createButton"); JButton saveButton = (JButton)TestUtilities.getField(panel, "saveButton"); JButton closeButton = (JButton)TestUtilities.getField(panel, "closeButton"); PhotoSizeAndQualityPanel sizePanel = (PhotoSizeAndQualityPanel)TestUtilities.getField(panel, "sizeAndQualityPanel"); final JSpinner widthSpinner = (JSpinner)TestUtilities.getField(sizePanel, "widthSpinner"); JSpinner heightSpinner = (JSpinner)TestUtilities.getField(sizePanel, "heightSpinner"); final JComboBox aspectRatioComboBox = (JComboBox)TestUtilities.getField(sizePanel, "aspectRatioComboBox"); JSlider qualitySlider = (JSlider)TestUtilities.getField(sizePanel, "qualitySlider"); tester.invokeAndWait(new Runnable() { public void run() { widthSpinner.setValue(200L); aspectRatioComboBox.setSelectedItem(AspectRatio.SQUARE_RATIO); } }); assertEquals("Height spinner has wrong value", 200, ((Number)heightSpinner.getValue()).intValue()); JSliderTester sliderTester = new JSliderTester(); for (int i = qualitySlider.getMinimum(); i <= qualitySlider.getMaximum(); i++) { sliderTester.actionSlide(qualitySlider, i); // Test image creation at each quality tester.click(createButton); if (i == qualitySlider.getMinimum()) { assertFalse("Rendering didn't start", saveButton.isEnabled()); } // Wait image is generated for (int j = 0; j < 1000 && !saveButton.isEnabled(); j++) { Thread.sleep(100); } assertTrue("Rendering didn't end", saveButton.isEnabled()); saveAndAssertMediaIsSaved(saveButton, ContentManager.ContentType.PNG, preferences.getLocalizedString(PhotoPanel.class, "savePhotoDialog.title"), photoCreationDialog, tester); } tester.click(closeButton); tester.close(frame); } public void testVideoCreation() throws InterruptedException, ComponentSearchException, NoSuchFieldException, IllegalAccessException, IOException { final JComponent view = (JComponent)this.homeController.getView(); // Create a frame that displays a home view JFrame frame = new JFrame("Video Creation Test"); frame.add(view); frame.pack(); showWindow(frame); JComponentTester tester = new JComponentTester(); tester.waitForIdle(); JDialog videoCreationDialog = showVideoCreationPanel(this.preferences, this.homeController, frame, tester); // Retrieve VideoPanel components VideoPanel panel = (VideoPanel)TestUtilities.findComponent(videoCreationDialog, VideoPanel.class); JProgressBar progressBar = (JProgressBar)TestUtilities.getField(panel, "progressBar"); JSlider qualitySlider = (JSlider)TestUtilities.getField(panel, "qualitySlider"); JButton createButton = (JButton)TestUtilities.getField(panel, "createButton"); JButton saveButton = (JButton)TestUtilities.getField(panel, "saveButton"); JButton closeButton = (JButton)TestUtilities.getField(panel, "closeButton"); JSliderTester sliderTester = new JSliderTester(); for (int i = qualitySlider.getMinimum(); i < qualitySlider.getMaximum(); i += 2) { sliderTester.actionSlide(qualitySlider, i); // Test image creation at quality 1 and 3 assertFalse("Progress bar is showing", progressBar.isShowing()); tester.click(createButton); assertTrue("Progress bar isn't showing", progressBar.isShowing()); // Wait image is generated for (int j = 0; j < 1000 && !saveButton.isEnabled(); j++) { Thread.sleep(100); } assertTrue("Rendering didn't end", saveButton.isEnabled()); saveAndAssertMediaIsSaved(saveButton, ContentManager.ContentType.MOV, preferences.getLocalizedString(VideoPanel.class, "saveVideoDialog.title"), videoCreationDialog, tester); } tester.click(closeButton); tester.close(frame); } /** * Returns the dialog that displays photo panel. */ private JDialog showPhotoCreationPanel(UserPreferences preferences, final HomeController controller, JFrame parent, JComponentTester tester) throws ComponentSearchException { tester.invokeLater(new Runnable() { public void run() { // Display dialog box later in Event Dispatch Thread to avoid blocking test thread ((JComponent)controller.getView()).getActionMap().get(HomePane.ActionType.CREATE_PHOTO).actionPerformed(null); } }); // Wait for 3D view to be shown tester.waitForFrameShowing(new AWTHierarchy(), preferences.getLocalizedString( PhotoPanel.class, "createPhoto.title")); // Check dialog box is displayed JDialog photoCreationDialog = (JDialog)new BasicFinder().find(parent, new ClassMatcher (JDialog.class, true)); assertTrue("Photo creation dialog not showing", photoCreationDialog.isShowing()); return photoCreationDialog; } /** * Returns the dialog that displays video panel. */ private JDialog showVideoCreationPanel(UserPreferences preferences, final HomeController controller, JFrame parent, JComponentTester tester) throws ComponentSearchException { tester.invokeLater(new Runnable() { public void run() { // Display dialog box later in Event Dispatch Thread to avoid blocking test thread ((JComponent)controller.getView()).getActionMap().get(HomePane.ActionType.CREATE_VIDEO).actionPerformed(null); } }); // Wait for 3D view to be shown tester.waitForFrameShowing(new AWTHierarchy(), preferences.getLocalizedString( VideoPanel.class, "createVideo.title")); // Check dialog box is displayed JDialog photoCreationDialog = (JDialog)new BasicFinder().find(parent, new ClassMatcher (JDialog.class, true)); assertTrue("Video creation dialog not showing", photoCreationDialog.isShowing()); return photoCreationDialog; } /** * Assert the generated media can be saved. */ private void saveAndAssertMediaIsSaved(JButton saveButton, ContentManager.ContentType contentType, final String fileDialogTitle, JDialog parent, JComponentTester tester) throws ComponentNotFoundException, MultipleComponentsFoundException, InterruptedException, IOException { File tmpDirectory = File.createTempFile("media", "dir"); tmpDirectory.delete(); assertTrue("Couldn't create tmp directory", tmpDirectory.mkdir()); String mediaBaseName = "test"; // Show save dialog box tester.click(saveButton); // Wait for file chooser to be shown tester.waitForFrameShowing(new AWTHierarchy(), fileDialogTitle); // Check dialog box is displayed final Dialog saveDialog = (Dialog)new BasicFinder().find(parent, new ClassMatcher (Dialog.class, true) { @Override public boolean matches(Component c) { if (super.matches(c)) { return ((Dialog)c).getTitle().equals(fileDialogTitle); } else { return false; } } }); assertTrue("Save dialog not showing", saveDialog.isShowing()); // Change file in print to PDF file chooser final JFileChooserTester fileChooserTester = new JFileChooserTester(); final JFileChooser fileChooser = (JFileChooser)new BasicFinder().find(saveDialog, new ClassMatcher(JFileChooser.class)); fileChooserTester.actionSetDirectory(fileChooser, tmpDirectory.getAbsolutePath()); fileChooserTester.actionSetFilename(fileChooser, mediaBaseName); // Select Ok option to hide dialog box fileChooserTester.actionApprove(fileChooser); assertFalse("Save dialog still showing", saveDialog.isShowing()); // Wait saving File mediaFile = new File(tmpDirectory, mediaBaseName + "." + contentType.toString().toLowerCase()); for (int i = 0; i < 100 && !mediaFile.exists(); i++) { Thread.sleep(100); } assertTrue("Media file " + mediaFile + " doesn't exist", mediaFile.exists()); assertTrue("Media file is empty", mediaFile.length() > 0); mediaFile.delete(); tmpDirectory.delete(); } }