/** * Copyright 2011 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ package com.jogamp.opengl.test.junit.jogl.acore; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.GLAnimatorControl; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.GLRunnable; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestGLException01NEWT extends UITestCase { static GLProfile glp; static int width, height; @SuppressWarnings("serial") static class AnimException extends RuntimeException { final Thread thread; final GLAnimatorControl animator; final GLAutoDrawable drawable; public AnimException(final Thread thread, final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause) { super(cause); this.thread = thread; this.animator = animator; this.drawable = drawable; } } @BeforeClass public static void initClass() { glp = GLProfile.getGL2ES2(); Assert.assertNotNull(glp); width = 512; height = 512; } public static void dumpThrowable(final Throwable t) { System.err.println("User caught exception "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName()); t.printStackTrace(); } protected void runTestGL(final GLCapabilities caps, final boolean onThread, final boolean throwInInit, final boolean throwInDisplay, final boolean throwInReshape, final boolean throwInInvoke, final boolean throwInDispose) throws InterruptedException { final GLWindow glWindow = GLWindow.create(caps); Assert.assertNotNull(glWindow); glWindow.setTitle(getTestMethodName()); final GearsES2 demo1 = new GearsES2(); demo1.setVerbose(false); glWindow.addGLEventListener(demo1); final AtomicInteger cleanInitCount = new AtomicInteger(); final AtomicInteger cleanDisposeCount = new AtomicInteger(); final AtomicInteger cleanDisplayCount = new AtomicInteger(); final AtomicInteger cleanReshapeCount = new AtomicInteger(); final AtomicInteger cleanInvokeCount = new AtomicInteger(); final AtomicInteger allInitCount = new AtomicInteger(); final AtomicInteger allDisposeCount = new AtomicInteger(); final AtomicInteger allDisplayCount = new AtomicInteger(); final AtomicInteger allReshapeCount = new AtomicInteger(); final AtomicInteger allInvokeCount = new AtomicInteger(); final AtomicInteger exceptionSent = new AtomicInteger(); glWindow.addGLEventListener(new GLEventListener() { @Override public void init(final GLAutoDrawable drawable) { if( throwInInit ) { exceptionSent.incrementAndGet(); throw new RuntimeException("<Injected GLEventListener exception in init: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">"); } } @Override public void dispose(final GLAutoDrawable drawable) { if( throwInDispose ) { exceptionSent.incrementAndGet(); throw new RuntimeException("<Injected GLEventListener exception in dispose: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">"); } } @Override public void display(final GLAutoDrawable drawable) { if( throwInDisplay ) { exceptionSent.incrementAndGet(); throw new RuntimeException("<Injected GLEventListener exception in display: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">"); } } @Override public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { if( throwInReshape ) { exceptionSent.incrementAndGet(); throw new RuntimeException("<Injected GLEventListener exception in reshape: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">"); } } }); final GLRunnable glRunnableInject = new GLRunnable() { @Override public boolean run(final GLAutoDrawable drawable) { if( throwInInvoke ) { exceptionSent.incrementAndGet(); throw new RuntimeException("<Injected GLEventListener exception in invoke: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">"); } return true; } }; final GLRunnable glRunnableCount = new GLRunnable() { @Override public boolean run(final GLAutoDrawable drawable) { if( 0 == exceptionSent.get() ) { cleanInvokeCount.incrementAndGet(); } allInvokeCount.incrementAndGet(); return true; } }; glWindow.addGLEventListener(new GLEventListener() { @Override public void init(final GLAutoDrawable drawable) { if( 0 == exceptionSent.get() ) { cleanInitCount.incrementAndGet(); } allInitCount.incrementAndGet(); } @Override public void dispose(final GLAutoDrawable drawable) { if( 0 == exceptionSent.get() ) { cleanDisposeCount.incrementAndGet(); } allDisposeCount.incrementAndGet(); } @Override public void display(final GLAutoDrawable drawable) { if( 0 == exceptionSent.get() ) { cleanDisplayCount.incrementAndGet(); } allDisplayCount.incrementAndGet(); } @Override public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { if( 0 == exceptionSent.get() ) { cleanReshapeCount.incrementAndGet(); } allReshapeCount.incrementAndGet(); } }); RuntimeException exceptionAtInitReshapeDisplay = null; RuntimeException exceptionAtInvoke = null; RuntimeException exceptionAtDispose = null; final List<AnimException> exceptionsAtGLAnimatorControl = new ArrayList<AnimException>(); final GLAnimatorControl.UncaughtExceptionHandler uncaughtExceptionHandler; final Animator animator; if( onThread ) { animator = null; uncaughtExceptionHandler = null; } else { animator = new Animator(glWindow); uncaughtExceptionHandler = new GLAnimatorControl.UncaughtExceptionHandler() { @Override public void uncaughtException(final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause) { final AnimException ae = new AnimException(animator.getThread(), animator, drawable, cause); exceptionsAtGLAnimatorControl.add(ae); dumpThrowable(ae); } }; animator.setUncaughtExceptionHandler(uncaughtExceptionHandler); } glWindow.setSize(width, height); if( !onThread ) { animator.setUpdateFPSFrames(1, null); animator.start(); } try { glWindow.setVisible(true); } catch (final RuntimeException re) { exceptionAtInitReshapeDisplay = re; dumpThrowable(re); } try { glWindow.invoke(true, glRunnableInject); glWindow.invoke(true, glRunnableCount); } catch (final RuntimeException re) { exceptionAtInvoke = re; dumpThrowable(re); } final long t0 = System.currentTimeMillis(); long t1 = t0; while(0 == exceptionSent.get() && ( onThread || animator.isAnimating() ) && t1-t0<duration ) { if( onThread ) { try { glWindow.display(); } catch (final RuntimeException re) { exceptionAtInitReshapeDisplay = re; dumpThrowable(re); } } Thread.sleep(100); t1 = System.currentTimeMillis(); } if( !onThread ) { animator.stop(); } try { glWindow.destroy(); } catch (final RuntimeException re) { exceptionAtDispose = re; dumpThrowable(re); } final boolean onAnimThread = !onThread && !throwInDispose; /** dispose happens on [AWT|NEWT] EDT, not on animator thread! */ System.err.println("This-Thread : "+onThread); System.err.println("Anim-Thread : "+onAnimThread); System.err.println("ExceptionSent : "+exceptionSent.get()); System.err.println("Exception @ Init/Reshape/Display: "+(null != exceptionAtInitReshapeDisplay)); System.err.println("Exception @ Invoke : "+(null != exceptionAtInvoke)); System.err.println("Exception @ Dispose : "+(null != exceptionAtDispose)); System.err.println("Exception @ GLAnimatorControl : "+exceptionsAtGLAnimatorControl.size()); System.err.println("Init Count : "+cleanInitCount.get()+" / "+allInitCount.get()); System.err.println("Reshape Count : "+cleanReshapeCount.get()+" / "+allReshapeCount.get()); System.err.println("Display Count : "+cleanDisplayCount.get()+" / "+allDisplayCount.get()); System.err.println("Invoke Count : "+cleanInvokeCount.get()+" / "+allInvokeCount.get()); System.err.println("Dispose Count : "+cleanDisposeCount.get()+" / "+allDisposeCount.get()); if( throwInInit || throwInReshape || throwInDisplay || throwInDispose || throwInInvoke ) { Assert.assertTrue("Not one exception sent, but "+exceptionSent.get(), 0 < exceptionSent.get()); if( onAnimThread ) { Assert.assertEquals("No exception forwarded from init to animator-handler", 1, exceptionsAtGLAnimatorControl.size()); Assert.assertNull("Exception forwarded from init, on-thread", exceptionAtInitReshapeDisplay); } if( throwInInit ) { if( !onAnimThread ) { Assert.assertNotNull("No exception forwarded from init, on-thread", exceptionAtInitReshapeDisplay); Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size()); } Assert.assertEquals("Init Count", 0, cleanInitCount.get()); Assert.assertEquals("Reshape Count", 0, cleanReshapeCount.get()); Assert.assertEquals("Display Count", 0, cleanDisplayCount.get()); Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get()); Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get()); } else if( throwInReshape ) { if( !onAnimThread ) { Assert.assertNotNull("No exception forwarded from reshape, on-thread", exceptionAtInitReshapeDisplay); Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size()); } Assert.assertEquals("Init Count", 1, cleanInitCount.get()); Assert.assertEquals("Reshape Count", 0, cleanReshapeCount.get()); Assert.assertEquals("Display Count", 0, cleanDisplayCount.get()); Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get()); Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get()); } else if( throwInDisplay ) { if( !onAnimThread ) { Assert.assertNotNull("No exception forwarded from display, on-thread", exceptionAtInitReshapeDisplay); Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size()); } Assert.assertEquals("Init Count", 1, cleanInitCount.get()); Assert.assertEquals("Reshape Count", 1, cleanReshapeCount.get()); Assert.assertEquals("Display Count", 0, cleanDisplayCount.get()); Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get()); Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get()); } else if( throwInInvoke ) { if( !onAnimThread ) { Assert.assertNotNull("No exception forwarded from invoke, on-thread", exceptionAtInvoke); Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size()); } Assert.assertEquals("Init Count", 1, cleanInitCount.get()); Assert.assertEquals("Reshape Count", 1, cleanReshapeCount.get()); Assert.assertTrue ("Display count not greater-equal 1, but "+cleanDisplayCount.get(), 1 <= cleanDisplayCount.get()); Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get()); Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get()); } else if( throwInDispose ) { if( !onAnimThread ) { Assert.assertNotNull("No exception forwarded from dispose, on-thread", exceptionAtDispose); Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size()); } Assert.assertEquals("Init Count", 1, cleanInitCount.get()); Assert.assertEquals("Reshape Count", 1, cleanReshapeCount.get()); Assert.assertTrue ("Display count not greater-equal 1, but "+cleanDisplayCount.get(), 1 <= cleanDisplayCount.get()); Assert.assertEquals("Invoke Count", 1, cleanInvokeCount.get()); Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get()); } } } @Test public void test01OnThreadAtInit() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, true /* onThread */, true /* init */, false /* display */, false /* reshape */, false /* invoke */, false /* dispose */); } @Test public void test02OnThreadAtReshape() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, true /* onThread */, false /* init */, false /* display */, true /* reshape */, false /* invoke */, false /* dispose */); } @Test public void test03OnThreadAtDisplay() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, true /* onThread */, false /* init */, true /* display */, false /* reshape */, false /* invoke */, false /* dispose */); } @Test public void test04OnThreadAtInvoke() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, true /* onThread */, false /* init */, true /* display */, false /* reshape */, true /* invoke */, false /* dispose */); } @Test public void test05OnThreadAtDispose() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, true /* onThread */, false /* init */, false /* display */, false /* reshape */, false /* invoke */, true /* dispose */); } @Test public void test11OffThreadAtInit() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, false /* onThread */, true /* init */, false /* display */, false /* reshape */, false /* invoke */, false /* dispose */); } @Test public void test12OffThreadAtReshape() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, false /* onThread */, false /* init */, false /* display */, true /* reshape */, false /* invoke */, false /* dispose */); } @Test public void test13OffThreadAtDisplay() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, false /* onThread */, false /* init */, true /* display */, false /* reshape */, false /* invoke */, false /* dispose */); } @Test public void test14OffThreadAtInvoke() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, false /* onThread */, false /* init */, true /* display */, false /* reshape */, true /* invoke */, false /* dispose */); } @Test public void test15OffThreadAtDispose() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); caps.setBackgroundOpaque(true); // default runTestGL(caps, false /* onThread */, false /* init */, false /* display */, false /* reshape */, false /* invoke */, true /* dispose */); } static long duration = 500; // ms public static void main(final String args[]) { boolean waitForKey = false; for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { i++; duration = MiscUtils.atol(args[i], duration); } else if(args[i].equals("-wait")) { waitForKey = true; } } if( waitForKey ) { UITestCase.waitForKey("main"); } org.junit.runner.JUnitCore.main(TestGLException01NEWT.class.getName()); } }