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);
});
}
}