Skip to content
Snippets Groups Projects
TestGridView.java 7.07 KiB
Newer Older
Torstein Strømme's avatar
Torstein Strømme committed
package no.uib.inf101.gridview;

// NOTE: This file does NOT demonstrate a good way to write a test!
// Most tests in this file are written in a way that makes it possible
// to test HOW the problem is solved instead of testing simply THAT
// the problem is solved. This is done to be able to test that the
// detailed instructions for the assignment are followed, and could
// provide hints in an educational setting in case something is off.
//
// In a real project, you should not test private methods, but instead
// test public or package-private methods. Test *what* the code does,
// not *how* it does it (like we do here).

import no.uib.inf101.colorgrid.*;
import org.junit.jupiter.api.Test;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import static org.junit.jupiter.api.Assertions.*;

public class TestGridView {

  @Test
  public void preferredSize() {
    GridView view = newGridView(null);
    assertNotNull(view, "Unable to create a new GridView object");
    assertNotNull(view.getPreferredSize(), "PreferredSize should not be null");
    assertEquals(400, view.getPreferredSize().width);
    assertEquals(300, view.getPreferredSize().height);
  }

  @Test
  public void drawCellsIllustratedSample() {
    // Sample case from assignment text
    IColorGrid sampleGrid = TestCellPositionToPixelConverter.newGridFromString(String.join("\n",
        "R--B",
        "----",
        "Y--G"
    ));
    Rectangle2D rect = new Rectangle2D.Double(30, 30, 340, 240);
    double margin = 30;
    RecordGraphics2D record = singleDrawCellsRun(sampleGrid, rect, margin);

    // Check that the correct number of calls were made
    assertEquals(12, record.getFillRecordShapes().size(),
        "The drawCells method call draw 12 rectangles in the illustrated sample case");

    assertColorIsDrawnOnceAt(record, Color.RED, new Rectangle2D.Double(60, 60, 47.5, 40));
    assertColorIsDrawnOnceAt(record, Color.BLUE, new Rectangle2D.Double(292.5, 60, 47.5, 40));
    assertColorIsDrawnOnceAt(record, Color.YELLOW, new Rectangle2D.Double(60, 200, 47.5, 40));
    assertColorIsDrawnOnceAt(record, Color.GREEN, new Rectangle2D.Double(292.5, 200, 47.5, 40));
  }

  @Test
  public void drawCellsIllustratedSampleTweak() {
    // Sample case from assignment text
    IColorGrid sampleGrid = TestCellPositionToPixelConverter.newGridFromString(String.join("\n",
        "R--B",
        "----",
        "Y--G"
    ));
    Rectangle2D rect = new Rectangle2D.Double(40, 20, 342, 243);
    double margin = 30;
    RecordGraphics2D record = singleDrawCellsRun(sampleGrid, rect, margin);

    // Check that the correct number of calls were made
    assertEquals(12, record.getFillRecordShapes().size());

    assertColorIsDrawnOnceAt(record, Color.RED, new Rectangle2D.Double(70, 50, 48, 41));
    assertColorIsDrawnOnceAt(record, Color.BLUE, new Rectangle2D.Double(304, 50, 48, 41));
    assertColorIsDrawnOnceAt(record, Color.YELLOW, new Rectangle2D.Double(70, 192, 48, 41));
    assertColorIsDrawnOnceAt(record, Color.GREEN, new Rectangle2D.Double(304, 192, 48, 41));
  }

  @Test
  public void drawCellsSingleCell() {
    // Sample case from assignment text
    IColorGrid sampleGrid = TestCellPositionToPixelConverter.newGridFromString("R");
    Rectangle2D rect = new Rectangle2D.Double(20, 30, 40, 50);
    double margin = 10;
    RecordGraphics2D record = singleDrawCellsRun(sampleGrid, rect, margin);

    // Check that the correct number of calls were made
    assertEquals(1, record.getFillRecordShapes().size());
    assertColorIsDrawnOnceAt(record, Color.RED, new Rectangle2D.Double(30, 40, 20, 30));
  }

  /////////////////////////////
  // Helper methods
  /////////////////////////////

  private void assertColorIsDrawnOnceAt(RecordGraphics2D record, Color color, Rectangle2D expectedRectangle) {
    int count = 0;
    for (int i=0; i<record.getFillRecordColors().size(); i++) {
      if (record.getFillRecordColors().get(i).equals(color)) {
        assertEquals(expectedRectangle, record.getFillRecordShapes().get(i),
            "Incorrect bounds for color "+ color
        );
        count++;
      }
    }
    assertEquals(1, count, "There should be exactly one rectangle with color "+ color);
  }

  static GridView newGridView(IColorGrid grid) {
    try {
      Constructor<?> constructor = GridView.class.getConstructor(IColorGrid.class);

      // Check that the constructor is public
      assertFalse(Modifier.isPrivate(constructor.getModifiers()),
          "The constructor GridView(IColorGrid) should not be private");

      // Create a new object using the constructor and return it
      return (GridView) constructor.newInstance(grid);
    } catch (NoSuchMethodException e) {
      if (grid != null) {
        fail("Could not find the constructor GridView(IColorGrid) in the GridView class");
      }
      try {
        Constructor<?> constructor = GridView.class.getConstructor();
        return (GridView) constructor.newInstance();
      } catch (NoSuchMethodException ex) {
        fail("Could not find the constructor GridView() or GridView(IColorGrid) in the GridView class");
      } catch (InvocationTargetException | InstantiationException | IllegalAccessException ex) {
        throw new RuntimeException(ex);
      }
    } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
      throw new RuntimeException(e);
    }
    throw new IllegalStateException("Should not be possible to reach this point");
  }

  public static RecordGraphics2D singleDrawCellsRun(
      IColorGrid grid, Rectangle2D rect, double margin) {
    // Get the "drawCells" method from the GridView class and invoke
    // the method with the fake Graphics2D object
    try {
      Method drawCell = GridView.class.getDeclaredMethod("drawCells",
          Graphics2D.class,
          CellColorCollection.class,
          CellPositionToPixelConverter.class
      );

      // Test that the method is static
      assertTrue(Modifier.isStatic(drawCell.getModifiers()),
          "The drawCells method should be static, and it should not use any instance variables");

      // Test that the method is private
      assertTrue(Modifier.isPrivate(drawCell.getModifiers()),
          "The drawCells method should be private");

      // Make the method accessible in case it is private
      drawCell.setAccessible(true);

      // Preparing a "fake" Graphics2D object that records stuff that
      // happens to it instead of actually drawing anything
      RecordGraphics2D g2 = new RecordGraphics2D();

      // Invoke the method
      drawCell.invoke(null, g2, grid, TestCellPositionToPixelConverter.getConverter(grid, rect, margin));
      return g2;
    } catch (NoSuchMethodException e) {
      fail("Could not find the method drawCells(Graphics2D, CellColorCollection,"
          + " CellPositionToPixelConverter) in the GridView class");
    } catch (InvocationTargetException | IllegalAccessException e) {
      throw new RuntimeException(e);
    }
    throw new IllegalStateException("Should not reach this point");
  }
}