/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 + "\".");
            }
        }
    }
}