TrianglesTestSuite.java
1: package com.wpollock.trianglestest;
2:
3: import static org.junit.Assert.*;
4:
5: import java.io.*; // For first demo test
6: import java.lang.ProcessBuilder.*; // For first demo test
7: import java.util.Arrays;
8:
9: import org.junit.Test;
10:
11: import com.wpollock.triangles.Triangles;
12:
13: /**
14: * Test Suite for Triangles program. Triangles.main is just a wrapper for
15: * {@link com.wpollock.triangles.Triangles#classify(java.lang.String[])},
16: * which returns a String. So we test that method.
17: *
18: * @author Wayne Pollock, Tampa Florida USA
19: */
20: public class TrianglesTestSuite {
21:
22: // In this implementation, a data-driven approach was used to save
23: // code and improve clarity. Here, each method tests several related
24: // sets of arguments. Note that the first failed test aborts the
25: // method, thus skipping the remaining checks. This was a trade-off
26: // I felt was worth while, as long as all the checks in a method checked
27: // the same thing, and the exception thrown and the data that caused it
28: // were included in the output.
29:
30: // If Triangles were not designed for testing, you would need to test
31: // this way (check the timings in the JUnit output!):
32:
33: @Test
34: public void testValidEquilateralDemo () {
35: // Test data (happy path):
36: String side1 = "3", side2 = "3", side3 = "3";
37: String expected = "Equilateral";
38:
39: // Run the Triangles Java program with the test data, collect the
40: // output:
41: ProcessBuilder pb =
42: new ProcessBuilder( "java", "com.wpollock.triangles.Triangles",
43: side1, side2, side3 );
44: // merger error output into regular output:
45: pb.redirectErrorStream(true);
46: pb.redirectOutput(Redirect.PIPE);
47: // Set the working directory:
48: File directory =
49: new File("C:\\Users\\wpollock\\Documents\\eclipse-workspace\\Triangles\\bin");
50: pb.directory(directory);
51: Process p;
52: String actual = null;
53: try {
54: p = pb.start();
55: // Run the program
56: BufferedReader in =
57: new BufferedReader(
58: new InputStreamReader( p.getInputStream() ) );
59: actual = in.readLine(); // Collect the results
60: } catch (Exception e) {
61: actual = e.toString();
62: }
63: assertEquals("Valid Equilateral Demo", expected, actual);
64: }
65:
66:
67: // Legal value (happy path) tests:
68:
69: @Test
70: public final void testValidEquilateral() {
71: String result = "Unknown";
72: try {
73: result = Triangles.classify("3", "3", "3");
74: } catch (Exception e ) {
75: result = "Exception Thrown:" + e;
76: }
77: assertEquals("Valid Equilateral", "Equilateral", result);
78: }
79:
80: @Test
81: public final void testValidIsosceles() {
82: String result = "Unknown";
83: // There are six isosceles tests: three each with the odd side
84: // shorter and longer.
85: String[][] dataSet = {
86: {"3", "3", "2"}, // Odd-side shorter
87: {"3", "2", "3"},
88: {"2", "3", "3"},
89: {"3", "3", "5"}, // Odd-side longer
90: {"3", "5", "3"},
91: {"5", "3", "3"},
92: };
93: for ( String[] data : dataSet ) {
94: try {
95: result = Triangles.classify(data);
96: } catch (Exception e ) {
97: result = "Exception Thrown:" + e;
98: }
99: assertEquals("Data " + Arrays.toString(data), "Isosceles", result);
100: }
101: }
102:
103: @Test
104: public final void testValidScalene() {
105: String result = "Unknown";
106: String[][] dataSet = { // It is important to check these are valid!
107: {"3", "4", "5"},
108: {"5", "4", "3"},
109: {"4", "5", "3"},
110:
111: // Tests with leading plus sign: not prohibited by the specs,
112: // so we assume it is allowed:
113: {"+5", "4", "3"},
114: {"5", "+4", "3"},
115: {"5", "4", "+3"}
116: };
117: for ( String[] data : dataSet ) {
118: try {
119: result = Triangles.classify(data);
120: } catch (Exception e ) {
121: result = "Exception Thrown:" + e;
122: }
123: assertEquals("Data " + Arrays.toString(data), "Scalene", result);
124: }
125: }
126:
127: // Boundary value tests:
128:
129: @Test
130: public final void testEquilateralBoundry() {
131: String result = "Unknown";
132: String[][] dataSet = {
133: {"10000000", "10000000", "10000000"},
134: {"1", "1", "1"},
135: {"" + (Integer.MAX_VALUE - 1), "" + (Integer.MAX_VALUE - 1),
136: "" + (Integer.MAX_VALUE - 1)},
137: {"" + Integer.MAX_VALUE, "" + Integer.MAX_VALUE,
138: "" + Integer.MAX_VALUE}
139: };
140: for ( String[] data : dataSet ) {
141: try {
142: result = Triangles.classify(data);
143: } catch (Exception e ) {
144: result = "exception thrown: " + e;
145: }
146: assertEquals("Data " + Arrays.toString(data), "Equilateral", result);
147: }
148: }
149:
150: @Test
151: public final void testEquilateralLeadingZeros() {
152: // Some systems treat leading zeros as an octal indicator,
153: // so "09" may cause an exception, or "10" may not equal "010":
154: String result = "Unknown";
155: String[][] dataSet = {
156: {"09", "09", "09"},
157: {"10", "010", "010"},
158: {"0010", "10", "00010"}
159: };
160: for ( String[] data : dataSet ) {
161: try {
162: result = Triangles.classify(data);
163: } catch (Exception e ) {
164: result = "Exception Thrown:" + e;
165: }
166: assertEquals("Data " + Arrays.toString(data), "Equilateral", result);
167: }
168: }
169:
170: // No Isosceles boundary tests, as those are the same as for scalene.
171:
172: @Test
173: public final void testScaleneBoundry() {
174: String result = "Unknown";
175: String[][] dataSet = {
176: {"65536", "65537", "2"},
177: {"10000000", "2", "10000001"},
178: {"2", "10000000", "10000001"},
179: {"100000", "100001", "100002"},
180: {"" + (Integer.MAX_VALUE - 3), "" + (Integer.MAX_VALUE - 2),
181: "" + (Integer.MAX_VALUE - 1)}
182: };
183: for ( String[] data : dataSet ) {
184: try {
185: result = Triangles.classify(data);
186: } catch (Exception e ) {
187: result = "Exception Thrown: " + e;
188: }
189: assertEquals("Data " + Arrays.toString(data), "Scalene", result);
190: }
191: }
192:
193: // Bad input test cases:
194:
195: @Test
196: public final void testZeroArguments() {
197: String result = "Unknown";
198: String[][] dataSet = {
199: {"0", "9", "10"},
200: {"9", "0", "10"},
201: {"9", "10", "0"},
202: {"0", "0", "10"},
203: {"0", "9", "0"},
204: {"9", "0", "0"},
205: {"0", "0", "0"},
206: {"00", "9", "10"}
207: };
208: for (String[] data : dataSet) {
209: try {
210: result = Triangles.classify(data);
211: // It's an error if we get to here:
212: fail("Data " + Arrays.toString(data)
213: + " should throw IllegalArgumentException,"
214: + " but returned \"" + result + "\".");
215: } catch (IllegalArgumentException e) { }
216: catch (Exception e) {
217: fail("Data " + Arrays.toString(data)
218: + " should throw IllegalArgumentException,"
219: + " but threw: " + e);
220: }
221: }
222: }
223:
224: @Test
225: public final void testIllegalArguments() {
226: String result = "Unknown";
227: String bigNum = "" + (1L + Integer.MAX_VALUE);
228:
229: String[][] dataSet = {
230: {"-2", "9", "10"}, // One negative value
231: {"9", "-2", "10"},
232: {"9", "10", "-2"},
233: {"-2", "-2", "3"}, // Two negative values
234: {"-2", "3", "-2"},
235: {"3", "-2", "-2"},
236: {"-2", "-2", "-2"}, // Three negative values
237: {"-02", "9", "10"},
238: {bigNum, "4", "5"}, // Non-int Integer
239: {"4", bigNum, "4"},
240: {"4", "5", bigNum},
241: };
242: for (String[] data : dataSet) {
243: try {
244: result = Triangles.classify(data);
245: // It's an error if we get to here:
246: fail("Data " + Arrays.toString(data)
247: + " should throw IllegalArgumentException,"
248: + " but returned \"" + result + "\".");
249: } catch (IllegalArgumentException e) { }
250: catch (Exception e) {
251: fail("Data " + Arrays.toString(data)
252: + " should throw IllegalArgumentException,"
253: + " but threw: " + e);
254: }
255: }
256: }
257:
258: // There's no good Exception to throw for invalid triangle (when the
259: // arguments are individually valid). For now, we use
260: // IllegalArgumentException, but a new RuntimeException type
261: // could (should?) be used instead.
262:
263: @Test
264: public final void testInvalidScalene() {
265: String result = "Unknown";
266: String[][] dataSet = {
267: {"1", "2", "3"}, // S + S == L
268: {"1", "3", "2"},
269: {"3", "2", "1"},
270: {"1", "2", "4"}, // S + S < L
271: {"1", "4", "2"},
272: {"4", "2", "1"}
273: };
274: for (String[] data : dataSet) {
275: try {
276: result = Triangles.classify(data);
277: // It's an error if we get to here:
278: fail("Data " + Arrays.toString(data)
279: + " should throw IllegalArgumentException,"
280: + " but returned \"" + result + "\".");
281: } catch (IllegalArgumentException e) { }
282: catch (Exception e) {
283: fail("Data " + Arrays.toString(data)
284: + " should throw IllegalArgumentException,"
285: + " but threw: " + e);
286: }
287: }
288: }
289:
290: @Test
291: public final void testInvalidIsosceles() {
292: String result = "Unknown";
293: String[][] dataSet = {
294: {"1", "2", "3"}, // S + S == L
295: {"1", "3", "2"},
296: {"3", "2", "1"},
297: {"1", "2", "4"}, // S + S < L
298: {"1", "4", "2"},
299: {"4", "2", "1"}
300: };
301: for (String[] data : dataSet) {
302: try {
303: result = Triangles.classify(data);
304: // It's an error if we get to here:
305: fail("Data " + Arrays.toString(data)
306: + " should throw IllegalArgumentException,"
307: + " but returned \"" + result + "\".");
308: } catch (IllegalArgumentException e) { }
309: catch (Exception e) {
310: fail("Data " + Arrays.toString(data)
311: + " should throw IllegalArgumentException,"
312: + " but threw: " + e);
313: }
314: }
315: }
316:
317: @Test
318: public final void testNonIntegerArguments() {
319: String result = "Unknown";
320: // Result codes: 'X', 'Y', 'Z' are positive integers, 'F' is non-integer.
321: String[][] dataSet = {
322: {"3.14", "4", "5"},
323: {"5", "3.14", "4"},
324: {"4", "5", "3.14"}
325: };
326: for (String[] data : dataSet) {
327: try {
328: result = Triangles.classify(data);
329: // It's an error if we get to here:
330: fail("Data " + Arrays.toString(data)
331: + " should throw IllegalArgumentException,"
332: + " but returned \"" + result + "\".");
333: } catch (IllegalArgumentException e) { }
334: catch (Exception e) {
335: fail("Data " + Arrays.toString(data)
336: + " should throw IllegalArgumentException,"
337: + " but threw: " + e);
338: }
339: }
340: }
341:
342: @Test
343: public final void testNonNumericArguments() {
344: String result = "Unknown";
345: String[][] dataSet = {
346: {"Foo", "4", "5"}, // One non-number argument
347: {"5", "Foo", "4"},
348: {"4", "5", "Foo"},
349: {"Foo", "Foo", "5"}, // Two non-number arguments
350: {"Foo", "4", "Foo"},
351: {"4", "Foo", "Foo"},
352: {"Foo", "Foo", "Foo"}, // Three non-number arguments
353: {"", "4", "5"}, // One zero-length argument
354: {"5", "", "4"},
355: {"4", "5", ""}
356: };
357: for (String[] data : dataSet) {
358: try {
359: result = Triangles.classify(data);
360: // It's an error if we get to here:
361: fail("Data " + Arrays.toString(data)
362: + " should throw IllegalArgumentException,"
363: + " but returned \"" + result + "\".");
364: } catch (IllegalArgumentException e) { }
365: catch (Exception e) {
366: fail("Data " + Arrays.toString(data)
367: + " should throw IllegalArgumentException,"
368: + " but threw: " + e);
369: }
370: }
371: }
372:
373: @Test
374: public final void testIncorrectNumberOfArguments() {
375: String result = "Unknown";
376: String[][] dataSet = {
377: {},
378: {"3"},
379: {"3", "4"},
380: {"3", "4", "5", "6"},
381: {"3", "4", "5", "6", "7", "8"}, // Twice as many args
382: };
383: for ( String[] data : dataSet ) {
384: try {
385: result = Triangles.classify(data);
386: // It's an error if we get to here:
387: fail("Data " + Arrays.toString(data)
388: + " should throw IllegalArgumentException,"
389: + " but returned \"" + result + "\".");
390: } catch (IllegalArgumentException e) { } // Expected result.
391: catch (Exception e) {
392: fail("Data " + Arrays.toString(data)
393: + " should throw IllegalArgumentException,"
394: + " but threw \"" + e + "\".");
395: }
396: }
397: }
398: }