/home/wpollock1/public_html/AJava/Triangles/TrianglesTestSuite.java
package com.wpollock.trianglestest;
import static org.junit.Assert.*;
import java.io.*; // For first demo test
import java.lang.ProcessBuilder.*; // For first demo test
import java.util.Arrays;
import org.junit.Test;
import com.wpollock.triangles.Triangles;
/**
* Test Suite for Triangles program. Triangles.main is just a wrapper for
* {@link com.wpollock.triangles.Triangles#classify(java.lang.String[])},
* which returns a String. So we test that method.
*
* @author Wayne Pollock, Tampa Florida USA
*/
public class TrianglesTestSuite {
// In this implementation, a data-driven approach was used to save
// code and improve clarity. Here, each method tests several related
// sets of arguments. Note that the first failed test aborts the
// method, thus skipping the remaining checks. This was a trade-off
// I felt was worth while, as long as all the checks in a method checked
// the same thing, and the exception thrown and the data that caused it
// were included in the output.
// If Triangles were not designed for testing, you would need to test
// this way (check the timings in the JUnit output!):
@Test
public void testValidEquilateralDemo () {
// Test data (happy path):
String side1 = "3", side2 = "3", side3 = "3";
String expected = "Equilateral";
// Run the Triangles Java program with the test data, collect the
// output:
ProcessBuilder pb =
new ProcessBuilder( "java", "com.wpollock.triangles.Triangles",
side1, side2, side3 );
// merger error output into regular output:
pb.redirectErrorStream(true);
pb.redirectOutput(Redirect.PIPE);
// Set the working directory:
File directory =
new File("C:\\Users\\wpollock\\Documents\\eclipse-workspace\\Triangles\\bin");
pb.directory(directory);
Process p;
String actual = null;
try {
p = pb.start();
// Run the program
BufferedReader in =
new BufferedReader(
new InputStreamReader( p.getInputStream() ) );
actual = in.readLine(); // Collect the results
} catch (Exception e) {
actual = e.toString();
}
assertEquals("Valid Equilateral Demo", expected, actual);
}
// Legal value (happy path) tests:
@Test
public final void testValidEquilateral() {
String result = "Unknown";
try {
result = Triangles.classify("3", "3", "3");
} catch (Exception e ) {
result = "Exception Thrown:" + e;
}
assertEquals("Valid Equilateral", "Equilateral", result);
}
@Test
public final void testValidIsosceles() {
String result = "Unknown";
// There are six isosceles tests: three each with the odd side
// shorter and longer.
String[][] dataSet = {
{"3", "3", "2"}, // Odd-side shorter
{"3", "2", "3"},
{"2", "3", "3"},
{"3", "3", "5"}, // Odd-side longer
{"3", "5", "3"},
{"5", "3", "3"},
};
for ( String[] data : dataSet ) {
try {
result = Triangles.classify(data);
} catch (Exception e ) {
result = "Exception Thrown:" + e;
}
assertEquals("Data " + Arrays.toString(data), "Isosceles", result);
}
}
@Test
public final void testValidScalene() {
String result = "Unknown";
String[][] dataSet = { // It is important to check these are valid!
{"3", "4", "5"},
{"5", "4", "3"},
{"4", "5", "3"},
// Tests with leading plus sign: not prohibited by the specs,
// so we assume it is allowed:
{"+5", "4", "3"},
{"5", "+4", "3"},
{"5", "4", "+3"}
};
for ( String[] data : dataSet ) {
try {
result = Triangles.classify(data);
} catch (Exception e ) {
result = "Exception Thrown:" + e;
}
assertEquals("Data " + Arrays.toString(data), "Scalene", result);
}
}
// Boundary value tests:
@Test
public final void testEquilateralBoundry() {
String result = "Unknown";
String[][] dataSet = {
{"10000000", "10000000", "10000000"},
{"1", "1", "1"},
{"" + (Integer.MAX_VALUE - 1), "" + (Integer.MAX_VALUE - 1),
"" + (Integer.MAX_VALUE - 1)},
{"" + Integer.MAX_VALUE, "" + Integer.MAX_VALUE,
"" + Integer.MAX_VALUE}
};
for ( String[] data : dataSet ) {
try {
result = Triangles.classify(data);
} catch (Exception e ) {
result = "exception thrown: " + e;
}
assertEquals("Data " + Arrays.toString(data), "Equilateral", result);
}
}
@Test
public final void testEquilateralLeadingZeros() {
// Some systems treat leading zeros as an octal indicator,
// so "09" may cause an exception, or "10" may not equal "010":
String result = "Unknown";
String[][] dataSet = {
{"09", "09", "09"},
{"10", "010", "010"},
{"0010", "10", "00010"}
};
for ( String[] data : dataSet ) {
try {
result = Triangles.classify(data);
} catch (Exception e ) {
result = "Exception Thrown:" + e;
}
assertEquals("Data " + Arrays.toString(data), "Equilateral", result);
}
}
// No Isosceles boundary tests, as those are the same as for scalene.
@Test
public final void testScaleneBoundry() {
String result = "Unknown";
String[][] dataSet = {
{"65536", "65537", "2"},
{"10000000", "2", "10000001"},
{"2", "10000000", "10000001"},
{"100000", "100001", "100002"},
{"" + (Integer.MAX_VALUE - 3), "" + (Integer.MAX_VALUE - 2),
"" + (Integer.MAX_VALUE - 1)}
};
for ( String[] data : dataSet ) {
try {
result = Triangles.classify(data);
} catch (Exception e ) {
result = "Exception Thrown: " + e;
}
assertEquals("Data " + Arrays.toString(data), "Scalene", result);
}
}
// Bad input test cases:
@Test
public final void testZeroArguments() {
String result = "Unknown";
String[][] dataSet = {
{"0", "9", "10"},
{"9", "0", "10"},
{"9", "10", "0"},
{"0", "0", "10"},
{"0", "9", "0"},
{"9", "0", "0"},
{"0", "0", "0"},
{"00", "9", "10"}
};
for (String[] data : dataSet) {
try {
result = Triangles.classify(data);
// It's an error if we get to here:
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but returned \"" + result + "\".");
} catch (IllegalArgumentException e) { }
catch (Exception e) {
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but threw: " + e);
}
}
}
@Test
public final void testIllegalArguments() {
String result = "Unknown";
String bigNum = "" + (1L + Integer.MAX_VALUE);
String[][] dataSet = {
{"-2", "9", "10"}, // One negative value
{"9", "-2", "10"},
{"9", "10", "-2"},
{"-2", "-2", "3"}, // Two negative values
{"-2", "3", "-2"},
{"3", "-2", "-2"},
{"-2", "-2", "-2"}, // Three negative values
{"-02", "9", "10"},
{bigNum, "4", "5"}, // Non-int Integer
{"4", bigNum, "4"},
{"4", "5", bigNum},
};
for (String[] data : dataSet) {
try {
result = Triangles.classify(data);
// It's an error if we get to here:
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but returned \"" + result + "\".");
} catch (IllegalArgumentException e) { }
catch (Exception e) {
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but threw: " + e);
}
}
}
// There's no good Exception to throw for invalid triangle (when the
// arguments are individually valid). For now, we use
// IllegalArgumentException, but a new RuntimeException type
// could (should?) be used instead.
@Test
public final void testInvalidScalene() {
String result = "Unknown";
String[][] dataSet = {
{"1", "2", "3"}, // S + S == L
{"1", "3", "2"},
{"3", "2", "1"},
{"1", "2", "4"}, // S + S < L
{"1", "4", "2"},
{"4", "2", "1"}
};
for (String[] data : dataSet) {
try {
result = Triangles.classify(data);
// It's an error if we get to here:
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but returned \"" + result + "\".");
} catch (IllegalArgumentException e) { }
catch (Exception e) {
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but threw: " + e);
}
}
}
@Test
public final void testInvalidIsosceles() {
String result = "Unknown";
String[][] dataSet = {
{"1", "2", "3"}, // S + S == L
{"1", "3", "2"},
{"3", "2", "1"},
{"1", "2", "4"}, // S + S < L
{"1", "4", "2"},
{"4", "2", "1"}
};
for (String[] data : dataSet) {
try {
result = Triangles.classify(data);
// It's an error if we get to here:
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but returned \"" + result + "\".");
} catch (IllegalArgumentException e) { }
catch (Exception e) {
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but threw: " + e);
}
}
}
@Test
public final void testNonIntegerArguments() {
String result = "Unknown";
// Result codes: 'X', 'Y', 'Z' are positive integers, 'F' is non-integer.
String[][] dataSet = {
{"3.14", "4", "5"},
{"5", "3.14", "4"},
{"4", "5", "3.14"}
};
for (String[] data : dataSet) {
try {
result = Triangles.classify(data);
// It's an error if we get to here:
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but returned \"" + result + "\".");
} catch (IllegalArgumentException e) { }
catch (Exception e) {
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but threw: " + e);
}
}
}
@Test
public final void testNonNumericArguments() {
String result = "Unknown";
String[][] dataSet = {
{"Foo", "4", "5"}, // One non-number argument
{"5", "Foo", "4"},
{"4", "5", "Foo"},
{"Foo", "Foo", "5"}, // Two non-number arguments
{"Foo", "4", "Foo"},
{"4", "Foo", "Foo"},
{"Foo", "Foo", "Foo"}, // Three non-number arguments
{"", "4", "5"}, // One zero-length argument
{"5", "", "4"},
{"4", "5", ""}
};
for (String[] data : dataSet) {
try {
result = Triangles.classify(data);
// It's an error if we get to here:
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but returned \"" + result + "\".");
} catch (IllegalArgumentException e) { }
catch (Exception e) {
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but threw: " + e);
}
}
}
@Test
public final void testIncorrectNumberOfArguments() {
String result = "Unknown";
String[][] dataSet = {
{},
{"3"},
{"3", "4"},
{"3", "4", "5", "6"},
{"3", "4", "5", "6", "7", "8"}, // Twice as many args
};
for ( String[] data : dataSet ) {
try {
result = Triangles.classify(data);
// It's an error if we get to here:
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but returned \"" + result + "\".");
} catch (IllegalArgumentException e) { } // Expected result.
catch (Exception e) {
fail("Data " + Arrays.toString(data)
+ " should throw IllegalArgumentException,"
+ " but threw \"" + e + "\".");
}
}
}
}