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: }