changeset 121:8c4a2784ba04

Added 1st version of a results graph generator.
author Pavel Tisnovsky <ptisnovs@redhat.com>
date Mon, 11 Nov 2013 13:07:52 +0100
parents 8c867e89e12e
children 178e1d1ccc9e
files ChangeLog src/org/thermostat/qa/reporter/ResultsGraphGenerator.java
diffstat 2 files changed, 231 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Nov 08 10:01:04 2013 +0100
+++ b/ChangeLog	Mon Nov 11 13:07:52 2013 +0100
@@ -1,3 +1,8 @@
+2013-11-11  Pavel Tisnovsky  <ptisnovs@redhat.com>
+
+	* src/org/thermostat/qa/reporter/ResultsGraphGenerator.java:
+	Added 1st version of a results graph generator.
+
 2013-11-08  Pavel Tisnovsky  <ptisnovs@redhat.com>
 
 	* src/org/thermostat/qa/reporter/GraphPagesGenerator.java:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/thermostat/qa/reporter/ResultsGraphGenerator.java	Mon Nov 11 13:07:52 2013 +0100
@@ -0,0 +1,226 @@
+/*
+
+    ThermostatQA - test framework for Thermostat Monitoring Tool
+
+    Copyright 2013 Red Hat, Inc.
+
+This file is part of ThermostatQA
+
+ThermostatQA is distributed under the GNU General Public License,
+version 2 or any later version (with a special exception described
+below, commonly known as the "Classpath Exception").
+
+A copy of GNU General Public License (GPL) is included in this
+distribution, in the file COPYING.
+
+Linking ThermostatQA code with other modules is making a combined work
+based on ThermostatQA.  Thus, the terms and conditions of the GPL
+cover the whole combination.
+
+As a special exception, the copyright holders of ThermostatQA give you
+permission to link this code with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on ThermostatQA code.  If you modify ThermostatQA, you may
+extend this exception to your version of the software, but you are
+not obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+*/
+
+package org.thermostat.qa.reporter;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+
+
+/**
+ * Simple generator for a graph (pie chart) containing test results which is
+ * used on the index.html page.
+ * 
+ * @author Pavel Tisnovsky <ptisnovs@redhat.com>
+ */
+public class ResultsGraphGenerator implements CommonGenerator
+{
+    /**
+     * 
+     */
+    private static final int ARC_BORDER = 20;
+
+    private int width;
+    private int height;
+    private int arcX;
+    private int arcY;
+    private int arcWidth;
+    private int arcHeight;
+    private Graphics2D graphics;
+
+    /**
+     * @param testResult
+     * @param graphSize
+     * @param string
+     * @throws IOException 
+     */
+    private void generateGraph(TestResult testResult, Dimension graphSize, String fileName) throws IOException {
+        setupGeometry(graphSize);
+        BufferedImage bitmap = createBitmap();
+        setGraphics(bitmap);
+        clearCanvas();
+
+        int totalTests = testResult.getPassed() + testResult.getFailed() + testResult.getError() + testResult.getIgnored();
+        int[] results = new int[4];
+        results[0] = testResult.getPassed();
+        results[1] = testResult.getFailed();
+        results[2] = testResult.getError();
+        results[3] = testResult.getIgnored();
+        Color[] arcColors = {Color.green, Color.red, Color.blue, Color.gray};
+
+        float startAngle = 0.0f;
+        float arcAngle;
+
+        for (int i = 0; i < results.length; i++) {
+            arcAngle = calcArcAngle(results[i], totalTests);
+            fillArc(arcColors[i], startAngle, arcAngle);
+            startAngle += arcAngle;
+        }
+
+        arcAngle = 0;
+        for (int i = 0; i < results.length; i++) {
+            arcAngle = calcArcAngle(results[i], totalTests);
+            drawArc(startAngle, arcAngle);
+            drawLabels(calcResultsPercentage(results[i], totalTests), startAngle, arcAngle);
+            startAngle += arcAngle;
+        }
+
+        ImageIO.write(bitmap, "png", new File(fileName));
+    }
+
+    /**
+     * @param testCount
+     * @param totalTests
+     * @return
+     */
+    private float calcArcAngle(int testCount, int totalTests) {
+        return (360.0f * testCount) / totalTests;
+    }
+
+    /**
+     * @param testCount
+     * @param totalTests
+     * @return
+     */
+    private int calcResultsPercentage(int testCount, int totalTests) {
+        return (int)((100.0f * testCount) / totalTests);
+    }
+
+    /**
+     * @param graphSize
+     */
+    private void setupGeometry(Dimension graphSize) {
+        this.width = graphSize.width;
+        this.height = graphSize.height;
+        this.arcX = ARC_BORDER;
+        this.arcY = ARC_BORDER;
+        this.arcWidth = this.width - (ARC_BORDER << 1);
+        this.arcHeight = this.height - (ARC_BORDER << 1);
+    }
+
+    /**
+     * @return
+     */
+    private BufferedImage createBitmap() {
+        return new BufferedImage(this.width, this.height, BufferedImage.TYPE_4BYTE_ABGR);
+    }
+
+    /**
+     * @param bitmap
+     */
+    private void setGraphics(BufferedImage bitmap) {
+        this.graphics = (Graphics2D) bitmap.getGraphics();
+        setRenderingHints();
+    }
+
+    /**
+     * Set the required rendering hints.
+     */
+    private void setRenderingHints() {
+        this.graphics.addRenderingHints(new RenderingHints(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY));
+        this.graphics.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
+    }
+
+    /**
+     * 
+     */
+    private void clearCanvas() {
+        final int rectWidth = this.width - 2;
+        final int rectHeight = this.height - 2;
+        this.graphics.setColor(Color.black);
+        this.graphics.setBackground(Color.white);
+        this.graphics.clearRect(1, 1, rectWidth, rectHeight);
+    }
+
+    /**
+     * @param startAngle
+     * @param arcAngle
+     */
+    private void drawArc(float startAngle, float arcAngle) {
+        final int centerX = this.width >> 1;
+        final int centerY = this.height >> 1;
+        final int radius = this.arcHeight >> 1;
+        double x1 = centerX + radius * Math.cos(Math.PI * startAngle / 180.0);
+        double y1 = centerY - radius * Math.sin(Math.PI * startAngle / 180.0);
+        //double x2 = centerX + radius * Math.cos(startAngle + arcAngle);
+        //double y2 = centerY + radius * Math.sin(startAngle + arcAngle);
+        this.graphics.setColor(Color.black);
+        this.graphics.drawArc(this.arcX, this.arcY, this.arcWidth, this.arcHeight, (int)startAngle, (int)arcAngle + 1);
+        this.graphics.drawLine(centerX, centerY, (int)x1, (int)y1);
+    }
+
+    /**
+     * @param percentage
+     * @param startAngle
+     * @param arcAngle
+     */
+    private void drawLabels(int percentage, float startAngle, float arcAngle) {
+        final int centerX = this.width >> 1;
+        final int centerY = this.height >> 1;
+        final int radius = (this.arcHeight >> 1) + 15;
+        final float angle = startAngle + arcAngle / 2.0f;
+        double x1 = centerX + radius * Math.cos(Math.PI * angle / 180.0);
+        double y1 = centerY - radius * Math.sin(Math.PI * angle / 180.0);
+        // TODO: getStringBounds or something like it would be much better
+        x1 -= 8;
+        this.graphics.drawString(percentage + "%", (int)x1, (int)y1);
+    }
+
+    /**
+     * @param arcColor
+     * @param startAngle
+     * @param arcAngle
+     */
+    private void fillArc(Color arcColor, float startAngle, float arcAngle) {
+        this.graphics.setColor(arcColor);
+        this.graphics.fillArc(this.arcX, this.arcY, this.arcWidth, this.arcHeight, (int)startAngle, (int)arcAngle + 1);
+    }
+
+    /**
+     * @param args
+     * @throws IOException 
+     */
+    public static void main(String[] args) throws IOException {
+        Dimension graphSize = new Dimension(256, 256);
+        TestResult testResult = new TestResult(100, 10, 5, 20);
+        new ResultsGraphGenerator().generateGraph(testResult, graphSize, "graph.png");
+    }
+
+}