public class DeckTester { public static void main(String[] args) { System.out.println("========================================"); System.out.println("Deck Tester"); System.out.println("========================================"); System.out.println(); System.out.println("PASS means the behavior was tested and worked."); System.out.println("FAIL means the behavior was tested and did not work."); System.out.println("NOT TESTED YET means an earlier behavior must work first."); System.out.println(); int passed = 0, failed = 0, notTested = 0; Deck deck = null; boolean sizeWorks = false; boolean dealWorks = false; boolean compositionWorks = false; // TEST 1 — no dependency on toString() System.out.println("----------------------------------------"); System.out.println("TEST 1 — Construct the Deck and size()"); System.out.println("----------------------------------------"); try { deck = new Deck(); System.out.println("Calling: new Deck()"); System.out.println("A Deck constructor calls build()."); System.out.println("Expected Size: 52"); System.out.println("Generated Size: " + deck.size()); sizeWorks = deck.size() == 52; if (sizeWorks) { System.out.println("PASS"); passed++; } else { System.out.println("FAIL"); System.out.println("Complete Deck construction, build(), and size() first."); failed++; } } catch (Throwable t) { fail(t); failed++; } System.out.println(); // TEST 2 — establish that deal returns a Card and decreases size. System.out.println("----------------------------------------"); System.out.println("TEST 2 — deal()"); System.out.println("----------------------------------------"); if (!sizeWorks) { notYet("deal() requires a Deck containing 52 Cards."); notTested++; } else { try { System.out.println("Starting Size: " + deck.size()); System.out.println("Calling: deal()"); Card dealt = deck.deal(); System.out.println("Expected Return: a Card"); System.out.println("Generated Return: " + (dealt == null ? "null" : dealt)); System.out.println("Expected Size: 51"); System.out.println("Generated Size: " + deck.size()); dealWorks = dealt != null && deck.size() == 51; if (dealWorks) { System.out.println("PASS"); passed++; } else { System.out.println("FAIL"); failed++; } } catch (Throwable t) { fail(t); failed++; } } System.out.println(); // TEST 3 — verify the actual 52-card composition without toString(). System.out.println("----------------------------------------"); System.out.println("TEST 3 — Deck composition"); System.out.println("----------------------------------------"); if (!dealWorks) { notYet("Deck composition is checked by dealing Cards, so deal() must work first."); notTested++; } else { try { deck.build(); int[] counts = new int[12]; boolean validValues = true; for (int i = 0; i < 52; i++) { Card c = deck.deal(); if (c == null) { validValues = false; break; } int value = c.getValue(); if (value < 2 || value > 11) { validValues = false; break; } counts[value]++; } compositionWorks = validValues && correctCounts(counts); System.out.println("Expected: 4 each of 2-9 and 11; 16 tens"); System.out.println("Generated Counts:"); for (int value = 2; value <= 11; value++) { System.out.println(" value " + value + ": " + counts[value]); } if (compositionWorks) { System.out.println("PASS"); passed++; } else { System.out.println("FAIL"); failed++; } } catch (Throwable t) { fail(t); failed++; } } System.out.println(); // TEST 4 — build should restore after TEST 3 emptied the Deck. System.out.println("----------------------------------------"); System.out.println("TEST 4 — build() restores the Deck"); System.out.println("----------------------------------------"); if (!compositionWorks) { notYet("build() restoration is checked after the Deck composition is verified."); notTested++; } else { try { System.out.println("Starting Size: " + deck.size()); System.out.println("Calling: build()"); deck.build(); System.out.println("Expected Size: 52"); System.out.println("Generated Size: " + deck.size()); if (deck.size() == 52) { System.out.println("PASS"); passed++; } else { System.out.println("FAIL"); failed++; } } catch (Throwable t) { fail(t); failed++; } } System.out.println(); // TEST 5 — shuffle tested through composition, not toString(). System.out.println("----------------------------------------"); System.out.println("TEST 5 — shuffle()"); System.out.println("----------------------------------------"); if (!compositionWorks) { notYet("shuffle() requires a correctly built Deck and working deal()."); notTested++; } else { try { deck.build(); deck.shuffle(); int[] counts = new int[12]; boolean validValues = true; for (int i = 0; i < 52; i++) { Card c = deck.deal(); if (c == null) { validValues = false; break; } int value = c.getValue(); if (value < 2 || value > 11) { validValues = false; break; } counts[value]++; } boolean preserved = validValues && correctCounts(counts); System.out.println("Expected Size After Dealing All: 0"); System.out.println("Generated Size: " + deck.size()); System.out.println("Expected Composition: preserved"); System.out.println("Generated Composition: " + (preserved ? "preserved" : "changed")); if (preserved && deck.size() == 0) { System.out.println("PASS"); passed++; } else { System.out.println("FAIL"); failed++; } } catch (Throwable t) { fail(t); failed++; } } System.out.println(); // TEST 6 — toString is independent and comes last. System.out.println("----------------------------------------"); System.out.println("TEST 6 — toString()"); System.out.println("----------------------------------------"); if (!compositionWorks) { notYet("toString() is tested after the Deck itself is known to be correct."); notTested++; } else { try { deck.build(); String generated = deck.toString(); int represented = countCards(generated); System.out.println("Expected Cards Represented: 52"); System.out.println("Generated Cards Represented: " + represented); System.out.println("Generated Output: " + generated); if (represented == 52) { System.out.println("PASS"); passed++; } else { System.out.println("FAIL"); failed++; } } catch (Throwable t) { fail(t); failed++; } } summary("DECK", passed, failed, notTested); if (failed == 0 && notTested == 0) { System.out.println(); System.out.println("Remember: this tester checks that shuffle preserves"); System.out.println("the Deck. It does not measure statistical shuffle quality."); } } private static boolean correctCounts(int[] counts) { for (int value = 2; value <= 9; value++) { if (counts[value] != 4) return false; } return counts[10] == 16 && counts[11] == 4; } private static int countCards(String text) { if (text == null) return -1; String cleaned = text.replace("[", "").replace("]", "").trim(); if (cleaned.isEmpty()) return 0; return cleaned.split(",").length; } private static void notYet(String reason) { System.out.println("NOT TESTED YET"); System.out.println(reason); } private static void fail(Throwable t) { System.out.println("FAIL"); System.out.println("Generated Error: " + t.getClass().getSimpleName() + (t.getMessage() == null ? "" : " — " + t.getMessage())); } private static void summary(String name, int passed, int failed, int notTested) { System.out.println(); System.out.println("========================================"); System.out.println(name + " TESTER RESULTS"); System.out.println("========================================"); System.out.println("Passed: " + passed); System.out.println("Failed: " + failed); System.out.println("Not tested yet: " + notTested); System.out.println(failed == 0 && notTested == 0 ? name + " TESTER PASS" : name + " NOT YET COMPLETE"); } }