package org.jooby.whoops; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.File; import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; import org.jooby.Err; import org.jooby.Err.Handler; import org.jooby.Request; import org.jooby.Response; import org.jooby.test.MockUnit; import org.jooby.whoops.SourceLocator.Source; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.slf4j.Logger; import com.google.common.collect.ImmutableMap; @RunWith(PowerMockRunner.class) @PrepareForTest({Whoops.class, Throwable.class, StackTraceElement.class }) public class WhoopsTest { @SuppressWarnings("rawtypes") @Test public void shouldFindClass() { Optional<Class> clazz = Whoops.findClass(getClass().getClassLoader(), WhoopsTest.class.getName()); assertEquals(true, clazz.isPresent()); } @SuppressWarnings("rawtypes") @Test public void shouldIgnoreMissingClass() { Optional<Class> clazz = Whoops.findClass(getClass().getClassLoader(), "XxNotFoUnd"); assertEquals(false, clazz.isPresent()); } @Test public void locationOf() { assertTrue(new File(Whoops.locationOf(Whoops.class)).exists()); assertEquals("rt.jar", Whoops.locationOf(Object.class)); } @Test public void frame() throws Exception { int line = 15; int[] range = {5, 15 }; String className = WhoopsApp.class.getName(); String fileName = WhoopsApp.class.getSimpleName() + ".java"; String methodName = "main"; String src = "{...}"; String message = "Something broken!"; new MockUnit(SourceLocator.class, Source.class, Throwable.class, StackTraceElement.class) .expect(unit -> { Throwable cause = unit.get(Throwable.class); expect(cause.getMessage()).andReturn(message); }) .expect(unit -> { StackTraceElement ste = unit.get(StackTraceElement.class); expect(ste.getLineNumber()).andReturn(line); expect(ste.getClassName()).andReturn(className); expect(ste.getFileName()).andReturn(fileName); expect(ste.getMethodName()).andReturn(methodName); }) .expect(unit -> { Source source = unit.get(Source.class); expect(source.range(line, 10)).andReturn(range); expect(source.source(range[0], range[1])).andReturn(src); expect(source.getPath()).andReturn(Paths.get(fileName)); SourceLocator locator = unit.get(SourceLocator.class); expect(locator.source(className)).andReturn(source); }) .run(unit -> { Map<String, Object> frame = Whoops.frame(getClass().getClassLoader(), unit.get(SourceLocator.class), unit.get(Throwable.class), unit.get(StackTraceElement.class)); assertEquals("WhoopsApp.java", frame.get("fileName")); assertEquals("main", frame.get("methodName")); assertEquals(15, frame.get("lineNumber")); assertEquals(6, frame.get("lineStart")); assertEquals(10, frame.get("lineNth")); assertEquals("target/test-classes", frame.get("location")); assertEquals("{...}", frame.get("source")); assertEquals("WhoopsApp", frame.get("type")); assertEquals( Arrays.asList(ImmutableMap.of("context", unit.get(Throwable.class).getClass().getName(), "text", message)), frame.get("comments")); }); } @Test public void frames() throws Exception { int line = 15; int[] range = {5, 15 }; String className = WhoopsApp.class.getName(); String fileName = WhoopsApp.class.getSimpleName() + ".java"; String methodName = "main"; String src = "{...}"; String message = "Something broken!"; new MockUnit(SourceLocator.class, Source.class, Throwable.class, StackTraceElement.class) .expect(unit -> { StackTraceElement ignored = unit.mock(StackTraceElement.class); expect(ignored.getClassName()).andReturn("org.jooby.internal.HttpHandlerImpl"); StackTraceElement[] stacktrace = {unit.get(StackTraceElement.class), ignored }; Throwable cause = unit.get(Throwable.class); expect(cause.getMessage()).andReturn(message); expect(cause.getStackTrace()).andReturn(stacktrace); }) .expect(unit -> { StackTraceElement ste = unit.get(StackTraceElement.class); expect(ste.getLineNumber()).andReturn(line); expect(ste.getClassName()).andReturn(className).times(2); expect(ste.getFileName()).andReturn(fileName); expect(ste.getMethodName()).andReturn(methodName); }) .expect(unit -> { Source source = unit.get(Source.class); expect(source.range(line, 10)).andReturn(range); expect(source.source(range[0], range[1])).andReturn(src); expect(source.getPath()).andReturn(Paths.get(fileName)); SourceLocator locator = unit.get(SourceLocator.class); expect(locator.source(className)).andReturn(source); }) .run(unit -> { List<Map<String, Object>> frames = Whoops.frames(getClass().getClassLoader(), unit.get(SourceLocator.class), unit.get(Throwable.class)); Map<String, Object> frame = frames.get(0); assertEquals("WhoopsApp.java", frame.get("fileName")); assertEquals("main", frame.get("methodName")); assertEquals(15, frame.get("lineNumber")); assertEquals(6, frame.get("lineStart")); assertEquals(10, frame.get("lineNth")); assertEquals("target/test-classes", frame.get("location")); assertEquals("{...}", frame.get("source")); assertEquals("WhoopsApp", frame.get("type")); assertEquals( Arrays.asList(ImmutableMap.of("context", unit.get(Throwable.class).getClass().getName(), "text", message)), frame.get("comments")); }); } @Test public void tryPage() throws Exception { Err err = new Err(500); Throwable cause = new IllegalStateException(); new MockUnit(Err.Handler.class, Request.class, Response.class, Logger.class) .expect(unit -> { Handler handler = unit.get(Err.Handler.class); handler.handle(unit.get(Request.class), unit.get(Response.class), err); expectLastCall().andThrow(cause); Logger log = unit.get(Logger.class); log.debug("execution of pretty err page resulted in exception", cause); }) .run(unit -> { Whoops.tryPage(unit.get(Err.Handler.class), unit.get(org.slf4j.Logger.class)) .handle(unit.get(Request.class), unit.get(Response.class), err); }); } }