package charts.builder;
import static charts.builder.ChartBuilderTest.getDatasource;
import static charts.builder.ChartBuilderTest.getDefaultTestingRegion;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Arrays.asList;
import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.fail;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.junit.Test;
import charts.Chart.UnsupportedFormatException;
import charts.ChartType;
import charts.Region;
import charts.builder.spreadsheet.TrendsSeagrassAbundanceBuilder;
import charts.representations.Format;
import com.google.common.collect.ImmutableMap;
public class ChartBuilderSizeTest {
private final static ChartBuilder chartBuilder = new DefaultChartBuilder(
new DataSourceFactory() {
@Override
public DataSource getDataSource(String id) throws Exception {
return getDatasource(ChartType.valueOf(id));
}
});
@Test
public void svgAndPngChartSize() throws Exception {
final List<ChartType> chartTypes = newArrayList(ChartType.values());
Collections.sort(chartTypes, new Comparator<ChartType>() {
@Override
public int compare(ChartType o1, ChartType o2) {
return o1.name().compareTo(o2.name());
}
});
for (final ChartType ct : chartTypes) {
try {
svgAndPngChartSize(ct);
} catch (UnsupportedFormatException e) {
fail(e.getMessage());
}
}
}
private void memstat(String msg) {
Runtime r = Runtime.getRuntime();
System.out.println(String.format("XXX %s, free %s, total %s, max %s",msg, hr(r.freeMemory()),
hr(r.totalMemory()), hr(r.maxMemory())));
}
private String hr(long bytes) {
return humanReadableByteCount(bytes, false);
}
// from http://stackoverflow.com/a/3758880
private String humanReadableByteCount(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
if (bytes < unit) return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
public void svgAndPngChartSize(ChartType chartType) throws Exception {
memstat("testing "+chartType.name());
long start = System.currentTimeMillis();
final List<Region> regions;
final Map<String, String> parameters;
switch (chartType) {
case TSA:
regions = asList(Region.CAPE_YORK);
parameters = ImmutableMap.of(TrendsSeagrassAbundanceBuilder.SUBREGION,
TrendsSeagrassAbundanceBuilder.Subregion.AP.name());
break;
//$CASES-OMITTED$
default:
regions = asList(getDefaultTestingRegion(chartType));
parameters = Collections.<String, String>emptyMap();
}
final charts.Chart chart = chartBuilder.getCharts(chartType.name(), chartType,
regions, parameters).get(0);
{
try {
Element svg = getSvgRoot(chart, new Dimension());
String[] viewBox = svg.attr("viewBox").split(" ");
assertThat(svg.attr("width")).isEqualTo(viewBox[2]);
assertThat(svg.attr("height")).isEqualTo(viewBox[3]);
checkDimensionsMatch(chartType, svg, getPngImage(chart, new Dimension()));
} catch(IndexOutOfBoundsException e) {
throw new RuntimeException(String.format(
"caught exception while testing chart type %s", chartType), e);
}
}
{
Element svg = getSvgRoot(chart, new Dimension(0, 127));
assertThat(svg.attr("width"))
.as(chartType+" unspecified width")
.isNotEqualTo("0");
assertThat(svg.attr("height")).isEqualTo("127");
checkDimensionsMatch(chartType, svg, getPngImage(chart, new Dimension(0, 127)));
}
{
Element svg = getSvgRoot(chart, new Dimension(383, 0));
assertThat(svg.attr("width")).isEqualTo("383");
assertThat(svg.attr("height"))
.as(chartType+" unspecified height")
.isNotEqualTo("0");
checkDimensionsMatch(chartType, svg, getPngImage(chart, new Dimension(383, 0)));
}
{
Element svg = getSvgRoot(chart, new Dimension(383, 127));
assertThat(svg.attr("width")).isEqualTo("383");
assertThat(svg.attr("height")).isEqualTo("127");
checkDimensionsMatch(chartType, svg, getPngImage(chart, new Dimension(383, 127)));
}
memstat(String.format("%s test took %s ms ",
chartType.name(), System.currentTimeMillis()-start));
}
private void checkDimensionsMatch(
ChartType ct, Element svg, BufferedImage png) {
String svgDimensions = svg.attr("width") + " x " + svg.attr("height");
String pngDimensions = png.getWidth() + " x " + png.getHeight();
assertThat(pngDimensions).as(ct+" PNG dimensions match SVG")
.isEqualTo(svgDimensions);
}
private Element getSvgRoot(charts.Chart chart, Dimension dimension)
throws UnsupportedFormatException {
return Jsoup.parse(new String(chart.outputAs(Format.SVG, dimension).getContent()))
.select("svg").get(0);
}
private BufferedImage getPngImage(charts.Chart chart, Dimension dimension)
throws UnsupportedFormatException {
try {
return ImageIO.read(new ByteArrayInputStream(chart.outputAs(Format.PNG, dimension)
.getContent()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}