From: Ben Soares Date: Tue, 1 Dec 2020 14:52:26 +0000 (+0000) Subject: JAL-3609 JAL-3775 Tests for jalview.bin.HiDPISetting X-Git-Tag: Develop-2_11_2_0-d20201215~15^2~4 X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=58f6e2a689afae0b869f28f8874cd735f0cfd129 JAL-3609 JAL-3775 Tests for jalview.bin.HiDPISetting --- diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 21092e6..2482dea 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -25,6 +25,7 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.Point; import java.awt.Rectangle; @@ -47,6 +48,7 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.awt.geom.AffineTransform; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; @@ -159,6 +161,8 @@ public class Desktop extends jalview.jbgui.GDesktop private JalviewChangeSupport changeSupport = new JalviewChangeSupport(); + public static boolean nosplash = false; + /** * news reader - null if it was never started. */ @@ -460,15 +464,17 @@ public class Desktop extends jalview.jbgui.GDesktop checkURLLinks(); // Spawn a thread that shows the splashscreen - - SwingUtilities.invokeLater(new Runnable() + if (!nosplash) { - @Override - public void run() + SwingUtilities.invokeLater(new Runnable() { - new SplashScreen(true); - } - }); + @Override + public void run() + { + new SplashScreen(true); + } + }); + } // Thread off a new instance of the file chooser - this reduces the time // it @@ -533,7 +539,6 @@ public class Desktop extends jalview.jbgui.GDesktop } }); desktop.addMouseListener(ma); - } /** @@ -2278,6 +2283,9 @@ public class Desktop extends jalview.jbgui.GDesktop 10, getHeight() - fm.getHeight()); } } + + // output debug scale message. Important for jalview.bin.HiDPISettingTest2 + Desktop.debugScaleMessage(Desktop.getDesktop().getGraphics()); } } @@ -3367,4 +3375,37 @@ public class Desktop extends jalview.jbgui.GDesktop } return result; } + + public static final String debugScaleMessage = "Desktop graphics transform scale="; + + private static boolean debugScaleMessageDone = false; + + public static void debugScaleMessage(Graphics g) + { + if (debugScaleMessageDone) + { + return; + } + // output used by tests to check HiDPI scaling settings in action + try + { + Graphics2D gg = (Graphics2D) g; + if (gg != null) + { + AffineTransform t = gg.getTransform(); + double scaleX = t.getScaleX(); + double scaleY = t.getScaleY(); + Cache.debug(debugScaleMessage + scaleX + " (X)"); + Cache.debug(debugScaleMessage + scaleY + " (Y)"); + debugScaleMessageDone = true; + } + else + { + Cache.debug("Desktop graphics null"); + } + } catch (Exception e) + { + Cache.debug(Cache.getStackTraceString(e)); + } + } } diff --git a/test/jalview/bin/HiDPISettingTest1.java b/test/jalview/bin/HiDPISettingTest1.java new file mode 100644 index 0000000..fd27a34 --- /dev/null +++ b/test/jalview/bin/HiDPISettingTest1.java @@ -0,0 +1,116 @@ +package jalview.bin; + +import static org.testng.Assert.assertEquals; + +import org.mockito.Mockito; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import jalview.gui.AlignFrame; +import jalview.gui.Desktop; +import jalview.gui.JvOptionPane; +import jalview.io.DataSourceType; +import jalview.io.FileLoader; + +/* + * Testing a HiDPI display is difficult without running in a HiDPI display. + * The gathering of screen size and resolution performed by jalview.bin.HiDPISetting + * is now farmed out into a separate class jalview.bin.ScreenInfo so it can be more + * easily Mocked in tests. + * Two sets of tests are performed. + * 1) testLinuxScalePropertyToActualTransform() sets the property that HiDPISetting + * uses (via jalview.bin.Launcher or getdown) to scale up Jalview, and then looks at + * the alignment panel graphics2d transform to see if it's been scaled by the same + * amount (in this case 4 -- unlikely to happen by accident!). + * 2) testHiDPISettingInit() which tests the calculation that HiDPISetting uses to + * decide from apparent screen information (mocked using Mockito in the tests) what + * scaling factor to set (it doesn't actually set it, just suggests it to + * jalview.bin.Launcher) + */ +public class HiDPISettingTest1 +{ + + AlignFrame af = null; + + @BeforeMethod(alwaysRun = true) + public void setUp() + { + JvOptionPane.setInteractiveMode(false); + JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); + Cache.loadProperties("test/jalview/bin/hidpiTestProps.jvprops"); + Jalview.main( + new String[] + { "-nosplash", "-nonews", "-noquestionnaire", + "-nowebservicediscovery" }); + + af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa", + DataSourceType.FILE); + + /* + * wait for Consensus thread to complete + */ + do + { + try + { + Thread.sleep(50); + } catch (InterruptedException x) + { + } + } while (af.getViewport().getCalcManager().isWorking()); + } + + @AfterClass(alwaysRun = true) + public void tearDown() + { + Desktop.instance.closeAll_actionPerformed(null); + } + + @Test(groups = { "Functional" }) + public void testHiDPISettingInit() + { + String scalePropertyName = "sun.java2d.uiScale"; + // ensure scale property is cleared (otherwise it will be re-used) + System.clearProperty(HiDPISetting.scalePropertyName); + + { // keep the mock under lock + // Ancient monitor -- no property change set + setMockScreen(1024, 768, 72); + assertEquals(HiDPISetting.getScalePropertyArg(), null); + + // Old monitor -- no property change set + setMockScreen(1200, 800, 96); + assertEquals(HiDPISetting.getScalePropertyArg(), null); + + // HD screen -- no property change set + setMockScreen(1920, 1080, 96); + assertEquals(HiDPISetting.getScalePropertyArg(), null); + + // 4K screen -- scale by 2 + setMockScreen(3180, 2160, 80); + assertEquals(HiDPISetting.getScalePropertyArg(), + "-D" + scalePropertyName + "=2"); + + // 4K screen with high dpi -- scale by 3 + setMockScreen(3180, 2160, 450); + assertEquals(HiDPISetting.getScalePropertyArg(), + "-D" + scalePropertyName + "=3"); + + // stupidly big screen -- scale by 8 + setMockScreen(19200, 10800, 72); + assertEquals(HiDPISetting.getScalePropertyArg(), + "-D" + scalePropertyName + "=8"); + } + } + + private void setMockScreen(int width, int height, int dpi) + { + HiDPISetting.clear(); + ScreenInfo mockScreenInfo = Mockito.spy(HiDPISetting.getScreenInfo()); + Mockito.doReturn(height).when(mockScreenInfo).getScreenHeight(); + Mockito.doReturn(width).when(mockScreenInfo).getScreenWidth(); + Mockito.doReturn(dpi).when(mockScreenInfo).getScreenResolution(); + HiDPISetting.setScreenInfo(mockScreenInfo); + } +} diff --git a/test/jalview/bin/HiDPISettingTest2.java b/test/jalview/bin/HiDPISettingTest2.java new file mode 100644 index 0000000..9851b09 --- /dev/null +++ b/test/jalview/bin/HiDPISettingTest2.java @@ -0,0 +1,223 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview 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. + * + * Jalview 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 Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.bin; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.concurrent.TimeUnit; + +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ScanResult; +import jalview.gui.Desktop; + +public class HiDPISettingTest2 +{ + private static final int TIMEOUT = 10; + + private static class Worker extends Thread + { + private final Process process; + + private BufferedReader outputReader; + + private BufferedReader errorReader; + + private boolean exited; + + private Worker(Process process) + { + this.process = process; + } + + @Override + public void run() + { + try + { + exited = process.waitFor(TIMEOUT, TimeUnit.SECONDS); + } catch (InterruptedException ignore) + { + return; + } + this.interrupt(); + this.process.destroy(); + } + + public BufferedReader getOutputReader() + { + return outputReader; + } + + public void setOutputReader(BufferedReader outputReader) + { + this.outputReader = outputReader; + } + + public BufferedReader getErrorReader() + { + return errorReader; + } + + public void setErrorReader(BufferedReader errorReader) + { + this.errorReader = errorReader; + } + } + + private static ClassGraph scanner = null; + + private static String classpath = null; + + private static String java_exe = null; + + public synchronized static String getClassPath() + { + if (scanner == null) + { + scanner = new ClassGraph(); + ScanResult scan = scanner.scan(); + classpath = scan.getClasspath(); + java_exe = System.getProperty("java.home") + File.separator + "bin" + + File.separator + "java"; + + } + while (classpath == null) + { + try + { + Thread.sleep(10); + } catch (InterruptedException x) + { + + } + } + return classpath; + } + + private Worker getJalviewDesktopRunner(String jvmArgs, String appArgs) + { + String classpath = getClassPath(); + String cmd = java_exe + " " + " -classpath " + classpath + " " + jvmArgs + + " jalview.bin.Jalview " + " " + + "-props test/jalview/bin/hidpiTestProps.jvprops " + appArgs; + Process proc = null; + Worker worker = null; + try + { + proc = Runtime.getRuntime().exec(cmd); + } catch (Throwable e) + { + e.printStackTrace(); + } + if (proc != null) + { + BufferedReader outputReader = new BufferedReader( + new InputStreamReader(proc.getInputStream())); + BufferedReader errorReader = new BufferedReader( + new InputStreamReader(proc.getErrorStream())); + worker = new Worker(proc); + worker.start(); + worker.setOutputReader(outputReader); + worker.setErrorReader(errorReader); + } + return worker; + } + + @BeforeTest(alwaysRun = true) + public void initialize() + { + new HiDPISettingTest2(); + } + + @Test(groups = { "Functional" }, dataProvider = "hidpiScaleArguments") + public void testHiDPISettings(int scale) + { + String jvmArgs = HiDPISetting.getScalePropertyArg(scale); + + String appArgs = " -open examples/uniref50.fa -nosplash -nonews -noquestionnaire -nousagestats -nowebservicediscovery"; + + Worker worker = getJalviewDesktopRunner(jvmArgs, appArgs); + assertNotNull(worker, "worker is null"); + + String ln = null; + int count = 0; + boolean scaleFound = false; + try + { + while ((ln = worker.getErrorReader().readLine()) != null) + { + if (++count > 100) + { + break; + } + if (ln.contains(Desktop.debugScaleMessage)) + { + String number = ln.substring(ln.indexOf(Desktop.debugScaleMessage) + + Desktop.debugScaleMessage.length()); + number = number.substring(0, number.indexOf(' ')); + try + { + double d = Double.valueOf(number); + + assertEquals(d, scale * 1.0); + scaleFound = true; + } catch (NumberFormatException e) + { + e.printStackTrace(); + Assert.fail( + "Debug scale message line '" + ln + "' gives number '" + + number + "' which could not be parsed"); + } + break; + } + } + } catch (IOException e) + { + e.printStackTrace(); + } + if (worker != null && worker.exited == false) + { + worker.interrupt(); + worker.process.destroy(); + } + if (!scaleFound) + { + Assert.fail("Did not find Debug scale message line '" + + Desktop.debugScaleMessage + "'"); + } + } + + @DataProvider(name = "hidpiScaleArguments") + public static Object[][] getHiDPIScaleArguments() + { + return new Object[][] { { 1 }, { 2 }, { 4 }, { 10 } }; + } +} diff --git a/test/jalview/bin/hidpiTestProps.jvprops b/test/jalview/bin/hidpiTestProps.jvprops new file mode 100644 index 0000000..c640dd1 --- /dev/null +++ b/test/jalview/bin/hidpiTestProps.jvprops @@ -0,0 +1,15 @@ +#---JalviewX Properties File--- +# HiDPI screen +SCREENGEOMETRY_WIDTH=3840 +SCREENGEOMETRY_HEIGHT=2160 +SCREEN_WIDTH=3000 +SCREEN_HEIGHT=2000 +USAGESTATS=false +STARTUP_FILE=examples/uniref50.fa +SHOW_STARTUP_FILE=false +FONT_STYLE=plain +FONT_SIZE=10 +ANTI_ALIAS=false +SHOW_JAVA_CONSOLE=false +DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/ +logs.Jalview.level=DEBUG