From 1090ef0d784abd1dfe6e29ef5d188147c9a0cba1 Mon Sep 17 00:00:00 2001 From: Benjamin Smith <122588740+BenSmith1202@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:23:16 -0500 Subject: [PATCH 01/11] Git fix --- .idea/codeStyles/codeStyleConfig.xml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .idea/codeStyles/codeStyleConfig.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file From da923432074c35886be3eae36ee18603ed7468d0 Mon Sep 17 00:00:00 2001 From: Benjamin Smith <122588740+BenSmith1202@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:45:52 -0500 Subject: [PATCH 02/11] added stats to gitignore --- .gitignore | 1 + guess-the-number-stats.csv | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2677823..3c90114 100644 --- a/.gitignore +++ b/.gitignore @@ -150,3 +150,4 @@ gradle-app.setting **/build/ # End of https://www.toptal.com/developers/gitignore/api/java,gradle,intellij +guess-the-number-stats.csv diff --git a/guess-the-number-stats.csv b/guess-the-number-stats.csv index aaf727f..3f2522d 100644 --- a/guess-the-number-stats.csv +++ b/guess-the-number-stats.csv @@ -41,3 +41,4 @@ "2025-03-09T14:52:22.376268400","11" "2025-03-09T21:21:12.080966400","10" "2025-03-09T21:22:42.471491","14" +"2026-02-05T11:26:50.907139200","13" From e1a3268735f75156096e745b7401412dddec1eea Mon Sep 17 00:00:00 2001 From: DavidOlinger <126510514+DavidOlinger@users.noreply.github.com> Date: Mon, 9 Feb 2026 23:10:12 -0500 Subject: [PATCH 03/11] refactored stats panel --- .gitignore | 3 +++ guess-the-number-stats.csv | 2 ++ src/StatsCalculator.java | 41 ++++++++++++++++++++++++++++++++++++++ src/StatsPanel.java | 25 ++++++----------------- 4 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 src/StatsCalculator.java diff --git a/.gitignore b/.gitignore index 2677823..41e2199 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,9 @@ cmake-build-*/ # Mongo Explorer plugin .idea/**/mongoSettings.xml +# GitHub Copilot plugin +.idea/**/copilot*.xml + # File-based project format *.iws diff --git a/guess-the-number-stats.csv b/guess-the-number-stats.csv index aaf727f..ad37fa5 100644 --- a/guess-the-number-stats.csv +++ b/guess-the-number-stats.csv @@ -41,3 +41,5 @@ "2025-03-09T14:52:22.376268400","11" "2025-03-09T21:21:12.080966400","10" "2025-03-09T21:22:42.471491","14" +"2026-02-09T14:42:34.598048300","14" +"2026-02-09T14:43:54.200692800","11" diff --git a/src/StatsCalculator.java b/src/StatsCalculator.java new file mode 100644 index 0000000..b9cc7ac --- /dev/null +++ b/src/StatsCalculator.java @@ -0,0 +1,41 @@ +/** + * Contains logic for calculating statistics about game results + * Separated from UI to enable unit testing + */ +public class StatsCalculator { + + /** + * Calculate the number of games in each bin defined by binEdges + * @param stats The game statistics data source + * @param binEdges Array defining bin boundaries. Bin i goes from binEdges[i] to binEdges[i+1]-1 (inclusive) + * The last bin includes binEdges[last] and all values above + * @return Array of counts, one per bin + */ + public int[] calculateBinCounts(GameStats stats, int[] binEdges) { + int[] binCounts = new int[binEdges.length]; + + for(int binIndex=0; binIndex resultsLabels; + private StatsCalculator statsCalculator; public StatsPanel(JPanel cardsPanel) { this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + statsCalculator = new StatsCalculator(); + JLabel title = new JLabel("Your Stats"); this.add(title); title.setAlignmentX(Component.CENTER_ALIGNMENT); @@ -94,27 +97,11 @@ private void updateResultsPanel(){ clearResults(); GameStats stats = new StatsFile(); + int[] binCounts = statsCalculator.calculateBinCounts(stats, BIN_EDGES); - for(int binIndex=0; binIndex Date: Mon, 9 Feb 2026 23:35:53 -0500 Subject: [PATCH 04/11] refactoed guessesPanel and Game OverPanel --- guess-the-number-stats.csv | 1 + src/ComputerGuessesGame.java | 67 +++++++++++++++++++++++++++++++++++ src/ComputerGuessesPanel.java | 36 +++++-------------- src/GameOverPanel.java | 11 +++--- src/GameResultFormatter.java | 30 ++++++++++++++++ 5 files changed, 111 insertions(+), 34 deletions(-) create mode 100644 src/ComputerGuessesGame.java create mode 100644 src/GameResultFormatter.java diff --git a/guess-the-number-stats.csv b/guess-the-number-stats.csv index 3f2522d..cf09dd2 100644 --- a/guess-the-number-stats.csv +++ b/guess-the-number-stats.csv @@ -42,3 +42,4 @@ "2025-03-09T21:21:12.080966400","10" "2025-03-09T21:22:42.471491","14" "2026-02-05T11:26:50.907139200","13" +"2026-02-09T23:26:49.733621500","9" diff --git a/src/ComputerGuessesGame.java b/src/ComputerGuessesGame.java new file mode 100644 index 0000000..d09e2dc --- /dev/null +++ b/src/ComputerGuessesGame.java @@ -0,0 +1,67 @@ +/** + * A game where the computer guesses a number between 1 and UPPER_BOUND + * Tracks the bounds, the current guess, and the number of guesses made + * + * Separated from UI to enable unit testing + */ +public class ComputerGuessesGame { + public final static int UPPER_BOUND = 1000; + public final static int LOWER_BOUND = 1; + + private int numGuesses; + private int lastGuess; + + // upperBound and lowerBound track the computer's knowledge about the correct number + // They are updated after each guess is made + private int upperBound; // correct number is <= upperBound + private int lowerBound; // correct number is >= lowerBound + + public ComputerGuessesGame() { + reset(); + } + + /** + * Resets the game to initial state and returns the first guess + */ + public int reset() { + numGuesses = 0; + upperBound = UPPER_BOUND; + lowerBound = LOWER_BOUND; + + lastGuess = (lowerBound + upperBound + 1) / 2; + return lastGuess; + } + + /** + * Records that the correct number is lower than the last guess + * @return the new guess + */ + public int recordLower() { + upperBound = Math.min(upperBound, lastGuess); + + lastGuess = (lowerBound + upperBound + 1) / 2; + numGuesses += 1; + return lastGuess; + } + + /** + * Records that the correct number is higher than the last guess + * @return the new guess + */ + public int recordHigher() { + lowerBound = Math.max(lowerBound, lastGuess + 1); + + lastGuess = (lowerBound + upperBound + 1) / 2; + numGuesses += 1; + return lastGuess; + } + + public int getLastGuess() { + return lastGuess; + } + + public int getNumGuesses() { + return numGuesses; + } +} + diff --git a/src/ComputerGuessesPanel.java b/src/ComputerGuessesPanel.java index 77b6d1b..506c39b 100644 --- a/src/ComputerGuessesPanel.java +++ b/src/ComputerGuessesPanel.java @@ -12,18 +12,10 @@ */ public class ComputerGuessesPanel extends JPanel { - private int numGuesses; - private int lastGuess; - - // upperBound and lowerBound track the computer's knowledge about the correct number - // They are updated after each guess is made - private int upperBound; // correct number is <= upperBound - private int lowerBound; // correct number is >= lowerBound + private ComputerGuessesGame game; public ComputerGuessesPanel(JPanel cardsPanel, Consumer gameFinishedCallback){ - numGuesses = 0; - upperBound = 1000; - lowerBound = 1; + game = new ComputerGuessesGame(); this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); @@ -41,11 +33,8 @@ public ComputerGuessesPanel(JPanel cardsPanel, Consumer gameFinished JButton lowerBtn = new JButton("Lower"); lowerBtn.addActionListener(e -> { - upperBound = Math.min(upperBound, lastGuess); - - lastGuess = (lowerBound + upperBound + 1) / 2; - numGuesses += 1; - guessMessage.setText("I guess " + lastGuess + "."); + int guess = game.recordLower(); + guessMessage.setText("I guess " + guess + "."); }); this.add(lowerBtn); lowerBtn.setAlignmentX(Component.CENTER_ALIGNMENT); @@ -56,7 +45,7 @@ public ComputerGuessesPanel(JPanel cardsPanel, Consumer gameFinished guessMessage.setText("I guess ___."); // Send the result of the finished game to the callback - GameResult result = new GameResult(false, lastGuess, numGuesses); + GameResult result = new GameResult(false, game.getLastGuess(), game.getNumGuesses()); gameFinishedCallback.accept(result); CardLayout cardLayout = (CardLayout) cardsPanel.getLayout(); @@ -68,11 +57,8 @@ public ComputerGuessesPanel(JPanel cardsPanel, Consumer gameFinished JButton higherBtn = new JButton("Higher"); higherBtn.addActionListener(e -> { - lowerBound = Math.max(lowerBound, lastGuess + 1); - - lastGuess = (lowerBound + upperBound + 1) / 2; - numGuesses += 1; - guessMessage.setText("I guess " + lastGuess + "."); + int guess = game.recordHigher(); + guessMessage.setText("I guess " + guess + "."); }); this.add(higherBtn); higherBtn.setAlignmentX(Component.CENTER_ALIGNMENT); @@ -80,12 +66,8 @@ public ComputerGuessesPanel(JPanel cardsPanel, Consumer gameFinished this.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentShown(java.awt.event.ComponentEvent e) { - numGuesses = 0; - upperBound = 1000; - lowerBound = 1; - - lastGuess = (lowerBound + upperBound + 1) / 2; - guessMessage.setText("I guess " + lastGuess + "."); + int guess = game.reset(); + guessMessage.setText("I guess " + guess + "."); } }); } diff --git a/src/GameOverPanel.java b/src/GameOverPanel.java index 52d97d0..07e28e8 100644 --- a/src/GameOverPanel.java +++ b/src/GameOverPanel.java @@ -16,12 +16,14 @@ public class GameOverPanel extends JPanel { private GameResult gameResult; + private GameResultFormatter formatter; private JLabel answerTxt; private JLabel numGuessesTxt; public GameOverPanel(JPanel cardsPanel){ this.gameResult = null; + this.formatter = new GameResultFormatter(); this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); @@ -72,13 +74,8 @@ public GameOverPanel(JPanel cardsPanel){ public void setGameResults(GameResult result){ this.gameResult = result; - answerTxt.setText("The answer was " + result.correctValue + "."); - if(result.numGuesses == 1){ - numGuessesTxt.setText((result.humanWasPlaying ? "You" : "I") + " guessed it on the first try!"); - } - else { - numGuessesTxt.setText("It took " + (result.humanWasPlaying ? "you" : "me") + " " + result.numGuesses + " guesses."); - } + answerTxt.setText(formatter.formatAnswerMessage(result)); + numGuessesTxt.setText(formatter.formatGuessesMessage(result)); if(result.humanWasPlaying){ // write stats to file diff --git a/src/GameResultFormatter.java b/src/GameResultFormatter.java new file mode 100644 index 0000000..85448b8 --- /dev/null +++ b/src/GameResultFormatter.java @@ -0,0 +1,30 @@ +/** + * Formats game result messages for display + * Separated from UI to enable unit testing + */ +public class GameResultFormatter { + + /** + * Formats the message showing what the correct answer was + * @param result the game result + * @return formatted answer message + */ + public String formatAnswerMessage(GameResult result) { + return "The answer was " + result.correctValue + "."; + } + + /** + * Formats the message showing how many guesses were taken + * @param result the game result + * @return formatted guesses message + */ + public String formatGuessesMessage(GameResult result) { + if(result.numGuesses == 1){ + return (result.humanWasPlaying ? "You" : "I") + " guessed it on the first try!"; + } + else { + return "It took " + (result.humanWasPlaying ? "you" : "me") + " " + result.numGuesses + " guesses."; + } + } +} + From b01daf08cb502e0ce100230a3851d24579642581 Mon Sep 17 00:00:00 2001 From: DavidOlinger <126510514+DavidOlinger@users.noreply.github.com> Date: Tue, 10 Feb 2026 22:42:48 -0500 Subject: [PATCH 05/11] tests --- COMP452-CodeTesting.iml | 2 + src/HumanGuessesGame.java | 7 + src/StatsCalculator.java | 3 - src/StatsRecordParser.java | 41 +++++ test/ComputerGuessesGameTest.java | 180 ++++++++++++++++++ test/GameResultFormatterTest.java | 170 +++++++++++++++++ test/GameResultTest.java | 118 ++++++++++++ test/HumanGuessesGameTest.java | 192 +++++++++++++++++++ test/README.txt | 16 ++ test/StatsCalculatorTest.java | 227 +++++++++++++++++++++++ test/StatsRecordParserTest.java | 295 ++++++++++++++++++++++++++++++ 11 files changed, 1248 insertions(+), 3 deletions(-) create mode 100644 src/StatsRecordParser.java create mode 100644 test/ComputerGuessesGameTest.java create mode 100644 test/GameResultFormatterTest.java create mode 100644 test/GameResultTest.java create mode 100644 test/HumanGuessesGameTest.java create mode 100644 test/StatsCalculatorTest.java create mode 100644 test/StatsRecordParserTest.java diff --git a/COMP452-CodeTesting.iml b/COMP452-CodeTesting.iml index 22bdac0..9fac510 100644 --- a/COMP452-CodeTesting.iml +++ b/COMP452-CodeTesting.iml @@ -10,5 +10,7 @@ + + \ No newline at end of file diff --git a/src/HumanGuessesGame.java b/src/HumanGuessesGame.java index c5faa6a..47b3e54 100644 --- a/src/HumanGuessesGame.java +++ b/src/HumanGuessesGame.java @@ -21,6 +21,13 @@ public class HumanGuessesGame { gameIsDone = false; } + // Constructor for testing - allows injecting a specific target value + HumanGuessesGame(int target){ + this.target = target; + numGuesses = 0; + gameIsDone = false; + } + GuessResult makeGuess(int value){ numGuesses += 1; diff --git a/src/StatsCalculator.java b/src/StatsCalculator.java index b9cc7ac..9c88051 100644 --- a/src/StatsCalculator.java +++ b/src/StatsCalculator.java @@ -6,9 +6,6 @@ public class StatsCalculator { /** * Calculate the number of games in each bin defined by binEdges - * @param stats The game statistics data source - * @param binEdges Array defining bin boundaries. Bin i goes from binEdges[i] to binEdges[i+1]-1 (inclusive) - * The last bin includes binEdges[last] and all values above * @return Array of counts, one per bin */ public int[] calculateBinCounts(GameStats stats, int[] binEdges) { diff --git a/src/StatsRecordParser.java b/src/StatsRecordParser.java new file mode 100644 index 0000000..9e88215 --- /dev/null +++ b/src/StatsRecordParser.java @@ -0,0 +1,41 @@ +import java.time.LocalDateTime; +import java.time.format.DateTimeParseException; + +/** + * Parses CSV record fields for game statistics + * Separated from file I/O to enable unit testing + */ +public class StatsRecordParser { + + /** + * Parse a timestamp string into a LocalDateTime + * @param timestampStr the string to parse + * @return the parsed LocalDateTime + * @throws DateTimeParseException if the string cannot be parsed + */ + public LocalDateTime parseTimestamp(String timestampStr) throws DateTimeParseException { + return LocalDateTime.parse(timestampStr); + } + + /** + * Parse a string into the number of guesses + * @param numGuessesStr the string to parse + * @return the parsed number of guesses + * @throws NumberFormatException if the string cannot be parsed as an integer + */ + public int parseNumGuesses(String numGuessesStr) throws NumberFormatException { + return Integer.parseInt(numGuessesStr); + } + + /** + * Check if a timestamp is within the specified number of days from now + * @param timestamp the timestamp to check + * @param days the number of days + * @return true if the timestamp is within the specified days + */ + public boolean isWithinDays(LocalDateTime timestamp, int days) { + LocalDateTime limit = LocalDateTime.now().minusDays(days); + return timestamp.isAfter(limit); + } +} + diff --git a/test/ComputerGuessesGameTest.java b/test/ComputerGuessesGameTest.java new file mode 100644 index 0000000..2e89e34 --- /dev/null +++ b/test/ComputerGuessesGameTest.java @@ -0,0 +1,180 @@ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for ComputerGuessesGame class + */ +public class ComputerGuessesGameTest { + + private ComputerGuessesGame game; + + @BeforeEach + void setUp() { + game = new ComputerGuessesGame(); + } + + // basic tests + + @Test + void testReset_ReturnsMiddleValue() { + int firstGuess = game.reset(); + + assertEquals(501, firstGuess); + } + + @Test + void testReset_NumGuessesIsZero() { + game.reset(); + + assertEquals(0, game.getNumGuesses()); + } + + @Test + void testConstructor_FirstGuessIsCorrect() { + assertEquals(501, game.getLastGuess()); + } + + @Test + void testConstructor_NumGuessesIsZero() { + assertEquals(0, game.getNumGuesses()); + } + + + + + @Test + void testRecordLower_UpdatesGuess() { + game.reset(); // lastGuess 501 + + int newGuess = game.recordLower(); + + assertEquals(251, newGuess); + } + + @Test + void testRecordLower_IncrementsNumGuesses() { + game.reset(); + game.recordLower(); + + assertEquals(1, game.getNumGuesses()); + } + + + + @Test + void testRecordHigher_UpdatesGuess() { + game.reset(); // lastGuess = 501 + + int newGuess = game.recordHigher(); + + assertEquals(751, newGuess); + } + + @Test + void testRecordHigher_IncrementsNumGuesses() { + game.reset(); + game.recordHigher(); + + assertEquals(1, game.getNumGuesses()); + } + + + // edge cases + + @Test + void testFindingTarget_AtMinBound() { + game.reset(); // 501 + int guess = 501; + + while(guess > 1) { + guess = game.recordLower(); + } + + assertEquals(1, guess); + } + + @Test + void testFindingTarget_AtMaxBound() { + game.reset(); // 501 + int guess = 501; + + while(guess < 1000) { + guess = game.recordHigher(); + } + + assertEquals(1000, guess); + } + + + + // getlastguess tests + + @Test + void testGetLastGuess_AfterReset() { + int guess = game.reset(); + + assertEquals(guess, game.getLastGuess()); + } + + @Test + void testGetLastGuess_AfterRecordLower() { + game.reset(); + int newGuess = game.recordLower(); + + assertEquals(newGuess, game.getLastGuess()); + } + + @Test + void testGetLastGuess_AfterRecordHigher() { + game.reset(); + int newGuess = game.recordHigher(); + + assertEquals(newGuess, game.getLastGuess()); + } + + // get numb guesses + + @Test + void testGetNumGuesses_IncreasesWithEachGuess() { + game.reset(); + assertEquals(0, game.getNumGuesses()); + + game.recordLower(); + assertEquals(1, game.getNumGuesses()); + + game.recordHigher(); + assertEquals(2, game.getNumGuesses()); + + game.recordLower(); + assertEquals(3, game.getNumGuesses()); + } + + + @Test + void testUpperBound_Value() { + assertEquals(1000, ComputerGuessesGame.UPPER_BOUND); + } + + @Test + void testLowerBound_Value() { + assertEquals(1, ComputerGuessesGame.LOWER_BOUND); + } + + + @Test + void testReset_AfterGameInProgress() { + game.reset(); + game.recordHigher(); + game.recordHigher(); + game.recordLower(); + + assertEquals(3, game.getNumGuesses()); + + int guess = game.reset(); + + assertEquals(501, guess); + assertEquals(0, game.getNumGuesses()); + } +} + diff --git a/test/GameResultFormatterTest.java b/test/GameResultFormatterTest.java new file mode 100644 index 0000000..a0b634b --- /dev/null +++ b/test/GameResultFormatterTest.java @@ -0,0 +1,170 @@ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for GameResultFormatter class + */ +public class GameResultFormatterTest { + + private GameResultFormatter formatter; + + @BeforeEach + void setUp() { + formatter = new GameResultFormatter(); + } + + // format message answer + + @Test + void testFormatAnswerMessage_BasicValue() { + GameResult result = new GameResult(true, 500, 5); + + String message = formatter.formatAnswerMessage(result); + + assertEquals("The answer was 500.", message); + } + + + + + @Test + void testFormatAnswerMessage_MinValue() { + GameResult result = new GameResult(true, 1, 10); + + String message = formatter.formatAnswerMessage(result); + + assertEquals("The answer was 1.", message); + } + + @Test + void testFormatAnswerMessage_MaxValue() { + GameResult result = new GameResult(true, 1000, 1); + + String message = formatter.formatAnswerMessage(result); + + assertEquals("The answer was 1000.", message); + } + + @Test + void testFormatAnswerMessage_HumanWasNotPlaying() { + GameResult result = new GameResult(false, 750, 8); + + String message = formatter.formatAnswerMessage(result); + + assertEquals("The answer was 750.", message); + } + + // format guesses message + + @Test + void testFormatGuessesMessage_HumanPlaying_OneGuess() { + GameResult result = new GameResult(true, 500, 1); + + String message = formatter.formatGuessesMessage(result); + + assertEquals("You guessed it on the first try!", message); + } + + @Test + void testFormatGuessesMessage_HumanPlaying_MultipleGuesses() { + GameResult result = new GameResult(true, 500, 5); + + String message = formatter.formatGuessesMessage(result); + + assertEquals("It took you 5 guesses.", message); + } + + @Test + void testFormatGuessesMessage_HumanPlaying_ManyGuesses() { + GameResult result = new GameResult(true, 500, 15); + + String message = formatter.formatGuessesMessage(result); + + assertEquals("It took you 15 guesses.", message); + } + + + @Test + void testFormatGuessesMessage_ComputerPlaying_OneGuess() { + GameResult result = new GameResult(false, 500, 1); + + String message = formatter.formatGuessesMessage(result); + + assertEquals("I guessed it on the first try!", message); + } + + + + + @Test + void testFormatGuessesMessage_ComputerPlaying_MultipleGuesses() { + GameResult result = new GameResult(false, 500, 7); + + String message = formatter.formatGuessesMessage(result); + + assertEquals("It took me 7 guesses.", message); + } + + + + + + @Test + void testFormatGuessesMessage_ComputerPlaying_Many() { + GameResult result = new GameResult(false, 500, 20); + + String message = formatter.formatGuessesMessage(result); + + assertEquals("It took me 20 guesses.", message); + } + + + // EDGE CASES + + @Test + void testFormatGuessesMessage_ZeroGuesses() { + // trying 0 + GameResult result = new GameResult(true, 500, 0); + + String message = formatter.formatGuessesMessage(result); + + + assertEquals("It took you 0 guesses.", message); + } + + @Test + void testFormatGuessesMessage_NegativeGuesses() { + // impossible num guesses + GameResult result = new GameResult(true, 500, -1); + + String message = formatter.formatGuessesMessage(result); + + // Should go to else branch since -1 != 1 + assertEquals("It took you -1 guesses.", message); + } + + @Test + void testFormatAnswerMessage_ZeroValue() { + // trying 0 + GameResult result = new GameResult(true, 0, 5); + + String message = formatter.formatAnswerMessage(result); + + assertEquals("The answer was 0.", message); + } + + + + + @Test + void testFormatAnswerMessage_NegativeValue() { + // try using negative answer + GameResult result = new GameResult(true, -100, 5); + + String message = formatter.formatAnswerMessage(result); + + assertEquals("The answer was -100.", message); + } +} + diff --git a/test/GameResultTest.java b/test/GameResultTest.java new file mode 100644 index 0000000..e7c0d85 --- /dev/null +++ b/test/GameResultTest.java @@ -0,0 +1,118 @@ +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for GameResult class + */ +public class GameResultTest { + + // constructor + + @Test + void testConstructor_HumanPlaying() { + GameResult result = new GameResult(true, 500, 10); + + assertTrue(result.humanWasPlaying); + assertEquals(500, result.correctValue); + assertEquals(10, result.numGuesses); + } + + @Test + void testConstructor_ComputerPlaying() { + GameResult result = new GameResult(false, 750, 8); + + assertFalse(result.humanWasPlaying); + assertEquals(750, result.correctValue); + assertEquals(8, result.numGuesses); + } + + + + + @Test + void testConstructor_MinValues() { + GameResult result = new GameResult(true, 1, 1); + + assertTrue(result.humanWasPlaying); + assertEquals(1, result.correctValue); + assertEquals(1, result.numGuesses); + } + + @Test + void testConstructor_MaxValues() { + GameResult result = new GameResult(true, 1000, 100); + + assertTrue(result.humanWasPlaying); + assertEquals(1000, result.correctValue); + assertEquals(100, result.numGuesses); + } + + // edge cases (spooky) + + @Test + void testConstructor_ZeroGuesses() { + GameResult result = new GameResult(true, 500, 0); + + assertEquals(0, result.numGuesses); + } + + @Test + void testConstructor_ZeroCorrectValue() { + GameResult result = new GameResult(true, 0, 5); + + assertEquals(0, result.correctValue); + } + + @Test + void testConstructor_NegativeValues() { + // Edge case - invalid data but class should accept it + GameResult result = new GameResult(false, -100, -5); + + assertEquals(-100, result.correctValue); + assertEquals(-5, result.numGuesses); + } + + + + + + + + @Test + void testConstructor_HumanWins_LowValue() { + GameResult result = new GameResult(true, 42, 7); + + assertTrue(result.humanWasPlaying); + assertEquals(42, result.correctValue); + assertEquals(7, result.numGuesses); + } + + @Test + void testConstructor_ComputerWins_HighValue() { + GameResult result = new GameResult(false, 999, 12); + + assertFalse(result.humanWasPlaying); + assertEquals(999, result.correctValue); + assertEquals(12, result.numGuesses); + } + + @Test + void testConstructor_FirstTryGuess() { + GameResult result = new GameResult(true, 501, 1); + + assertTrue(result.humanWasPlaying); + assertEquals(501, result.correctValue); + assertEquals(1, result.numGuesses); + } + + + + + @Test + void testConstructor_LargeNumberOfGuesses() { + GameResult result = new GameResult(true, 500, 1000); + + assertEquals(1000, result.numGuesses); + } +} + diff --git a/test/HumanGuessesGameTest.java b/test/HumanGuessesGameTest.java new file mode 100644 index 0000000..b950966 --- /dev/null +++ b/test/HumanGuessesGameTest.java @@ -0,0 +1,192 @@ +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for HumanGuessesGame class + */ +public class HumanGuessesGameTest { + + + @Test + void testMakeGuess_TooLow() { + HumanGuessesGame game = new HumanGuessesGame(500); + + GuessResult result = game.makeGuess(250); + + assertEquals(GuessResult.LOW, result); + } + + + + + @Test + void testMakeGuess_TooHigh() { + HumanGuessesGame game = new HumanGuessesGame(500); + + GuessResult result = game.makeGuess(750); + + assertEquals(GuessResult.HIGH, result); + } + + @Test + void testMakeGuess_Correct() { + HumanGuessesGame game = new HumanGuessesGame(500); + + GuessResult result = game.makeGuess(500); + + assertEquals(GuessResult.CORRECT, result); + } + + @Test + void testMakeGuess_EdgeCase_MinValue() { + HumanGuessesGame game = new HumanGuessesGame(1); + + assertEquals(GuessResult.CORRECT, game.makeGuess(1)); + assertEquals(GuessResult.HIGH, game.makeGuess(2)); + } + + @Test + void testMakeGuess_EdgeCase_MaxValue() { + HumanGuessesGame game = new HumanGuessesGame(1000); + + assertEquals(GuessResult.CORRECT, game.makeGuess(1000)); + assertEquals(GuessResult.LOW, game.makeGuess(999)); + } + + @Test + void testMakeGuess_OneOffLow() { + HumanGuessesGame game = new HumanGuessesGame(500); + + GuessResult result = game.makeGuess(499); + + assertEquals(GuessResult.LOW, result); + } + + @Test + void testMakeGuess_OneOffHigh() { + HumanGuessesGame game = new HumanGuessesGame(500); + + GuessResult result = game.makeGuess(501); + + assertEquals(GuessResult.HIGH, result); + } + + + + @Test + void testGetNumGuesses_InitiallyZero() { + HumanGuessesGame game = new HumanGuessesGame(500); + + assertEquals(0, game.getNumGuesses()); + } + + @Test + void testGetNumGuesses_AfterOneGuess() { + HumanGuessesGame game = new HumanGuessesGame(500); + game.makeGuess(250); + + assertEquals(1, game.getNumGuesses()); + } + + @Test + void testGetNumGuesses_AfterMultipleGuesses() { + HumanGuessesGame game = new HumanGuessesGame(500); + game.makeGuess(250); + game.makeGuess(375); + game.makeGuess(437); + game.makeGuess(468); + game.makeGuess(500); + + assertEquals(5, game.getNumGuesses()); + } + + @Test + void testGetNumGuesses_CountsIncorrectAndCorrectGuesses() { + HumanGuessesGame game = new HumanGuessesGame(500); + game.makeGuess(100); // wrong + game.makeGuess(900); // wrong + game.makeGuess(500); // correct + + assertEquals(3, game.getNumGuesses()); + } + + // ========== Tests for isDone method ========== + + @Test + void testIsDone_InitiallyFalse() { + HumanGuessesGame game = new HumanGuessesGame(500); + + assertFalse(game.isDone()); + } + + @Test + void testIsDone_AfterIncorrectGuess() { + HumanGuessesGame game = new HumanGuessesGame(500); + game.makeGuess(250); + + assertFalse(game.isDone()); + } + + @Test + void testIsDone_AfterCorrectGuess() { + //i think this is a found bug + + HumanGuessesGame game = new HumanGuessesGame(500); + game.makeGuess(500); + + assertTrue(game.isDone()); + } + + + + + + + @Test + void testFullGame_BinarySearchPattern() { + HumanGuessesGame game = new HumanGuessesGame(750); + + // Simulate binary search + assertEquals(GuessResult.LOW, game.makeGuess(500)); + assertEquals(GuessResult.HIGH, game.makeGuess(875)); + assertEquals(GuessResult.LOW, game.makeGuess(687)); + assertEquals(GuessResult.CORRECT, game.makeGuess(750)); + + assertEquals(4, game.getNumGuesses()); + } + + @Test + void testGame_GuessOnFirstTry() { + HumanGuessesGame game = new HumanGuessesGame(42); + + GuessResult result = game.makeGuess(42); + + assertEquals(GuessResult.CORRECT, result); + assertEquals(1, game.getNumGuesses()); + } + + + @Test + void testUpperBound_Value() { + assertEquals(1000, HumanGuessesGame.UPPER_BOUND); + } + + + + + + + + + + + + + + + + + + +} + diff --git a/test/README.txt b/test/README.txt index ec7a9b3..d90cb81 100644 --- a/test/README.txt +++ b/test/README.txt @@ -1 +1,17 @@ Put your JUnit test classes and test doubles in this folder. + +Partner Information: +[Add your partner's name here] + +Test Files: +- HumanGuessesGameTest.java - Tests for the human guessing game logic +- ComputerGuessesGameTest.java - Tests for the computer guessing game logic +- GameResultFormatterTest.java - Tests for game result message formatting +- StatsCalculatorTest.java - Tests for statistics calculation (uses dependency injection) +- GameResultTest.java - Tests for the GameResult data class +- StatsRecordParserTest.java - Tests for CSV record parsing and formatting exceptions + +Note: JUnit 5 library is required to run these tests. +Add org.junit.jupiter:junit-jupiter:5.8.2 (or later) from Maven. + + diff --git a/test/StatsCalculatorTest.java b/test/StatsCalculatorTest.java new file mode 100644 index 0000000..2e3ccb6 --- /dev/null +++ b/test/StatsCalculatorTest.java @@ -0,0 +1,227 @@ +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for StatsCalculator class + * Uses dependency injection with a test double to avoid file I/O + */ +public class StatsCalculatorTest { + + /** + * Test double class that implements GameStats for testing purposes + * This allows us to control the data returned without reading from a file + */ + //using dependency injection + private static class TestGameStats extends GameStats { + private final int[] gamesPerNumGuesses; + private final int maxGuesses; + + public TestGameStats(int[] gamesPerNumGuesses) { + this.gamesPerNumGuesses = gamesPerNumGuesses; + this.maxGuesses = gamesPerNumGuesses.length; + } + + @Override + public int numGames(int numGuesses) { + if (numGuesses < 0 || numGuesses >= gamesPerNumGuesses.length) { + return 0; + } + return gamesPerNumGuesses[numGuesses]; + } + + @Override + public int maxNumGuesses() { + return maxGuesses; + } + } + + // ========== Tests for calculateBinCounts ========== + + @Test + void testCalculateBinCounts_BasicCase() { + // Create test data: games took 1-10 guesses, with varying counts + // Index 0 = 0 guesses (not used), Index 1 = 1 guess, etc. + int[] gameData = {0, 5, 10, 8, 6, 4, 3, 2, 1, 1, 0}; // 11 elements, max is 10 + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 4, 7, 10}; // Bins: 1-4, 4-7, 7-10, 10+ + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + assertEquals(4, binCounts.length); + } + + @Test + void testCalculateBinCounts_EmptyStats() { + int[] gameData = new int[11]; // All zeros + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 5, 10}; + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + assertEquals(0, binCounts[0]); + assertEquals(0, binCounts[1]); + assertEquals(0, binCounts[2]); + } + + @Test + void testCalculateBinCounts_SingleBin() { + int[] gameData = {0, 2, 3, 4, 5, 6}; // 6 elements + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1}; // Single bin from 1 to max + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + assertEquals(1, binCounts.length); + // Should sum all games from index 1 to 5 (maxNumGuesses-1) + // 2 + 3 + 4 + 5 + 6 = 20? But maxNumGuesses is 6, so it goes from 1 to 5 + // 2 + 3 + 4 + 5 = 14 + } + + @Test + void testCalculateBinCounts_AllGamesInFirstBin() { + int[] gameData = {0, 10, 5, 0, 0, 0}; // Games only in 1-2 guesses + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 3, 5}; + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + // First bin (1-3): 10 + 5 + 0 = 15 + // Wait - need to check the algorithm. lowerBound=1, upperBound=3 + // It includes both bounds, so 1, 2, 3 -> 10 + 5 + 0 = 15 + } + + @Test + void testCalculateBinCounts_AllGamesInLastBin() { + int[] gameData = {0, 0, 0, 0, 0, 5, 10, 8}; // Games only in 5+ guesses + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 3, 5}; + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + // Last bin starts at 5 and goes to maxNumGuesses (8) + // Should sum indices 5, 6, 7 -> 5 + 10 + 8 = 23 + } + + @Test + void testCalculateBinCounts_VerifyBinBoundaries() { + // Test that bin boundaries work correctly + // Each guess count has exactly 1 game + int[] gameData = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; // 10 games total, indices 1-10 + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 4, 7, 10}; + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + // Bin 0: 1-4 inclusive -> 4 games + // Bin 1: 4-7 inclusive -> 4 games (but 4 is counted in bin 0 too?) + // Need to understand the exact algorithm... + // Looking at code: lowerBound=1, upperBound=4 (from binEdges[1]) + // numGuesses from 1 to 4 inclusive + assertEquals(4, binCounts.length); + } + + @Test + void testCalculateBinCounts_LargeNumbers() { + int[] gameData = new int[101]; // Support up to 100 guesses + gameData[50] = 1000; + gameData[51] = 500; + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 50, 75}; + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + assertEquals(3, binCounts.length); + } + + @Test + void testCalculateBinCounts_TwoBins() { + int[] gameData = {0, 5, 5, 5, 5, 5}; // 5 games per guess count, 1-5 guesses + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 3}; // Two bins + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + assertEquals(2, binCounts.length); + // First bin (1-3): 5 + 5 + 5 = 15 + // Second bin (3 to max=6): indices 3, 4, 5 = 5 + 5 + 5 = 15 + } + + @Test + void testCalculateBinCounts_NonOverlappingBins() { + // Test with specific known values + int[] gameData = {0, 2, 4, 6, 8, 10, 12}; // indices 0-6 + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 3, 5}; + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + // Bin 0: lowerBound=1, upperBound=3 -> 2+4+6 = 12 + // Bin 1: lowerBound=3, upperBound=5 -> 6+8+10 = 24 + // Bin 2 (last): lowerBound=5 to maxNumGuesses=7 -> indices 5,6 = 10+12 = 22 + assertEquals(3, binCounts.length); + } + + @Test + void testCalculateBinCounts_WithZeroGames() { + int[] gameData = {0, 0, 5, 0, 10, 0, 0}; + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 4}; + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + assertEquals(2, binCounts.length); + } + + // ========== Edge case tests ========== + + @Test + void testCalculateBinCounts_SingleElementBinEdges() { + int[] gameData = {0, 1, 2, 3, 4, 5}; + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {3}; // Only one bin starting at 3 + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + assertEquals(1, binCounts.length); + // Last bin from 3 to max (6): 3+4+5 = 12 + } + + @Test + void testCalculateBinCounts_MaxGuessesEqualsZero() { + int[] gameData = {}; // Empty data + TestGameStats stats = new TestGameStats(gameData); + + int[] binEdges = {1, 5, 10}; + StatsCalculator calculator = new StatsCalculator(); + + int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + // All bins should be 0 + assertEquals(0, binCounts[0]); + assertEquals(0, binCounts[1]); + assertEquals(0, binCounts[2]); + } +} + diff --git a/test/StatsRecordParserTest.java b/test/StatsRecordParserTest.java new file mode 100644 index 0000000..8f20b50 --- /dev/null +++ b/test/StatsRecordParserTest.java @@ -0,0 +1,295 @@ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +import static org.junit.jupiter.api.Assertions.*; + +import java.time.LocalDateTime; +import java.time.format.DateTimeParseException; + +/** + * Unit tests for StatsRecordParser class + * Tests parsing logic and formatting exceptions + */ +public class StatsRecordParserTest { + + private StatsRecordParser parser; + + @BeforeEach + void setUp() { + parser = new StatsRecordParser(); + } + + // ========== Tests for parseTimestamp - valid cases ========== + + @Test + void testParseTimestamp_ValidFormat() { + String timestampStr = "2026-02-10T14:30:00"; + + LocalDateTime result = parser.parseTimestamp(timestampStr); + + assertEquals(2026, result.getYear()); + assertEquals(2, result.getMonthValue()); + assertEquals(10, result.getDayOfMonth()); + assertEquals(14, result.getHour()); + assertEquals(30, result.getMinute()); + } + + @Test + void testParseTimestamp_Midnight() { + String timestampStr = "2026-01-01T00:00:00"; + + LocalDateTime result = parser.parseTimestamp(timestampStr); + + assertEquals(0, result.getHour()); + assertEquals(0, result.getMinute()); + } + + @Test + void testParseTimestamp_EndOfDay() { + String timestampStr = "2026-12-31T23:59:59"; + + LocalDateTime result = parser.parseTimestamp(timestampStr); + + assertEquals(23, result.getHour()); + assertEquals(59, result.getMinute()); + assertEquals(59, result.getSecond()); + } + + @Test + void testParseTimestamp_WithoutSeconds() { + String timestampStr = "2026-02-10T14:30"; + + LocalDateTime result = parser.parseTimestamp(timestampStr); + + assertEquals(14, result.getHour()); + assertEquals(30, result.getMinute()); + assertEquals(0, result.getSecond()); + } + + // ========== Tests for parseTimestamp - invalid cases (expect exceptions) ========== + + @Test + void testParseTimestamp_InvalidFormat_ThrowsException() { + String timestampStr = "invalid-date"; + + assertThrows(DateTimeParseException.class, () -> { + parser.parseTimestamp(timestampStr); + }); + } + + @Test + void testParseTimestamp_EmptyString_ThrowsException() { + String timestampStr = ""; + + assertThrows(DateTimeParseException.class, () -> { + parser.parseTimestamp(timestampStr); + }); + } + + @Test + void testParseTimestamp_WrongDateFormat_ThrowsException() { + // US date format instead of ISO + String timestampStr = "02/10/2026 14:30:00"; + + assertThrows(DateTimeParseException.class, () -> { + parser.parseTimestamp(timestampStr); + }); + } + + @Test + void testParseTimestamp_InvalidMonth_ThrowsException() { + String timestampStr = "2026-13-10T14:30:00"; + + assertThrows(DateTimeParseException.class, () -> { + parser.parseTimestamp(timestampStr); + }); + } + + @Test + void testParseTimestamp_InvalidDay_ThrowsException() { + String timestampStr = "2026-02-30T14:30:00"; + + assertThrows(DateTimeParseException.class, () -> { + parser.parseTimestamp(timestampStr); + }); + } + + @Test + void testParseTimestamp_MissingTime_ThrowsException() { + String timestampStr = "2026-02-10"; + + assertThrows(DateTimeParseException.class, () -> { + parser.parseTimestamp(timestampStr); + }); + } + + @Test + void testParseTimestamp_Null_ThrowsException() { + assertThrows(NullPointerException.class, () -> { + parser.parseTimestamp(null); + }); + } + + // ========== Tests for parseNumGuesses - valid cases ========== + + @Test + void testParseNumGuesses_ValidNumber() { + String numGuessesStr = "10"; + + int result = parser.parseNumGuesses(numGuessesStr); + + assertEquals(10, result); + } + + @Test + void testParseNumGuesses_SingleDigit() { + String numGuessesStr = "5"; + + int result = parser.parseNumGuesses(numGuessesStr); + + assertEquals(5, result); + } + + @Test + void testParseNumGuesses_LargeNumber() { + String numGuessesStr = "1000"; + + int result = parser.parseNumGuesses(numGuessesStr); + + assertEquals(1000, result); + } + + @Test + void testParseNumGuesses_Zero() { + String numGuessesStr = "0"; + + int result = parser.parseNumGuesses(numGuessesStr); + + assertEquals(0, result); + } + + @Test + void testParseNumGuesses_NegativeNumber() { + // Should parse negative numbers (even if invalid in context) + String numGuessesStr = "-5"; + + int result = parser.parseNumGuesses(numGuessesStr); + + assertEquals(-5, result); + } + + // ========== Tests for parseNumGuesses - invalid cases (expect exceptions) ========== + + @Test + void testParseNumGuesses_NonNumeric_ThrowsException() { + String numGuessesStr = "abc"; + + assertThrows(NumberFormatException.class, () -> { + parser.parseNumGuesses(numGuessesStr); + }); + } + + @Test + void testParseNumGuesses_EmptyString_ThrowsException() { + String numGuessesStr = ""; + + assertThrows(NumberFormatException.class, () -> { + parser.parseNumGuesses(numGuessesStr); + }); + } + + @Test + void testParseNumGuesses_Decimal_ThrowsException() { + String numGuessesStr = "5.5"; + + assertThrows(NumberFormatException.class, () -> { + parser.parseNumGuesses(numGuessesStr); + }); + } + + @Test + void testParseNumGuesses_WithSpaces_ThrowsException() { + String numGuessesStr = " 10 "; + + // Integer.parseInt does not trim whitespace + assertThrows(NumberFormatException.class, () -> { + parser.parseNumGuesses(numGuessesStr); + }); + } + + @Test + void testParseNumGuesses_MixedContent_ThrowsException() { + String numGuessesStr = "10abc"; + + assertThrows(NumberFormatException.class, () -> { + parser.parseNumGuesses(numGuessesStr); + }); + } + + @Test + void testParseNumGuesses_Null_ThrowsException() { + assertThrows(NumberFormatException.class, () -> { + parser.parseNumGuesses(null); + }); + } + + // ========== Tests for isWithinDays ========== + + @Test + void testIsWithinDays_Recent_ReturnsTrue() { + // A timestamp from 1 day ago should be within 30 days + LocalDateTime timestamp = LocalDateTime.now().minusDays(1); + + assertTrue(parser.isWithinDays(timestamp, 30)); + } + + @Test + void testIsWithinDays_Old_ReturnsFalse() { + // A timestamp from 60 days ago should NOT be within 30 days + LocalDateTime timestamp = LocalDateTime.now().minusDays(60); + + assertFalse(parser.isWithinDays(timestamp, 30)); + } + + @Test + void testIsWithinDays_ExactlyAtLimit_ReturnsFalse() { + // A timestamp from exactly 30 days ago should NOT be after the limit + // (it's not AFTER, it's equal to or before) + LocalDateTime timestamp = LocalDateTime.now().minusDays(30); + + assertFalse(parser.isWithinDays(timestamp, 30)); + } + + @Test + void testIsWithinDays_JustInsideLimit_ReturnsTrue() { + // A timestamp from just under 30 days ago + LocalDateTime timestamp = LocalDateTime.now().minusDays(29).minusHours(23); + + assertTrue(parser.isWithinDays(timestamp, 30)); + } + + @Test + void testIsWithinDays_Now_ReturnsTrue() { + LocalDateTime timestamp = LocalDateTime.now(); + + assertTrue(parser.isWithinDays(timestamp, 30)); + } + + @Test + void testIsWithinDays_Future_ReturnsTrue() { + // Future dates should be "within" the past 30 days (they're after the limit) + LocalDateTime timestamp = LocalDateTime.now().plusDays(5); + + assertTrue(parser.isWithinDays(timestamp, 30)); + } + + @Test + void testIsWithinDays_ZeroDays() { + // With 0 days, only future timestamps should return true + LocalDateTime recent = LocalDateTime.now().minusMinutes(1); + LocalDateTime future = LocalDateTime.now().plusMinutes(1); + + assertFalse(parser.isWithinDays(recent, 0)); + assertTrue(parser.isWithinDays(future, 0)); + } +} + From 742d7f8ca47f8a233df230f75c9b7c1b5316ed27 Mon Sep 17 00:00:00 2001 From: Benjamin Smith <122588740+BenSmith1202@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:19:19 -0500 Subject: [PATCH 06/11] Computer guesses game --- test/ComputerGuessesGameTest.java | 1 + test/HumanGuessesGameTest.java | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/test/ComputerGuessesGameTest.java b/test/ComputerGuessesGameTest.java index 2e89e34..ae53762 100644 --- a/test/ComputerGuessesGameTest.java +++ b/test/ComputerGuessesGameTest.java @@ -2,6 +2,7 @@ import org.junit.jupiter.api.BeforeEach; import static org.junit.jupiter.api.Assertions.*; + /** * Unit tests for ComputerGuessesGame class */ diff --git a/test/HumanGuessesGameTest.java b/test/HumanGuessesGameTest.java index b950966..2aa157f 100644 --- a/test/HumanGuessesGameTest.java +++ b/test/HumanGuessesGameTest.java @@ -6,7 +6,10 @@ */ public class HumanGuessesGameTest { + // most of these tests use configuration injection to inject values for + // "target" + //Dependency Injection (on HumanGuessesGame) @Test void testMakeGuess_TooLow() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -16,9 +19,7 @@ void testMakeGuess_TooLow() { assertEquals(GuessResult.LOW, result); } - - - + //ensures that when a guess is too high, the game properly records that result @Test void testMakeGuess_TooHigh() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -28,6 +29,7 @@ void testMakeGuess_TooHigh() { assertEquals(GuessResult.HIGH, result); } + // ensures that proper guesses are recorded @Test void testMakeGuess_Correct() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -37,6 +39,7 @@ void testMakeGuess_Correct() { assertEquals(GuessResult.CORRECT, result); } + // checks the edge case where the target is 1 @Test void testMakeGuess_EdgeCase_MinValue() { HumanGuessesGame game = new HumanGuessesGame(1); @@ -45,6 +48,7 @@ void testMakeGuess_EdgeCase_MinValue() { assertEquals(GuessResult.HIGH, game.makeGuess(2)); } + // checks the egde case when the target is 1000 @Test void testMakeGuess_EdgeCase_MaxValue() { HumanGuessesGame game = new HumanGuessesGame(1000); @@ -53,6 +57,7 @@ void testMakeGuess_EdgeCase_MaxValue() { assertEquals(GuessResult.LOW, game.makeGuess(999)); } + //checks edge case where target is one higher than the guess @Test void testMakeGuess_OneOffLow() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -62,6 +67,7 @@ void testMakeGuess_OneOffLow() { assertEquals(GuessResult.LOW, result); } + //same but when target is lower @Test void testMakeGuess_OneOffHigh() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -72,7 +78,7 @@ void testMakeGuess_OneOffHigh() { } - + // tests that numGuesses is properly initialized @Test void testGetNumGuesses_InitiallyZero() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -80,6 +86,7 @@ void testGetNumGuesses_InitiallyZero() { assertEquals(0, game.getNumGuesses()); } + //tests that numguesses is incremented @Test void testGetNumGuesses_AfterOneGuess() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -88,6 +95,7 @@ void testGetNumGuesses_AfterOneGuess() { assertEquals(1, game.getNumGuesses()); } + //tests that numguesses is incremented consistently @Test void testGetNumGuesses_AfterMultipleGuesses() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -100,6 +108,7 @@ void testGetNumGuesses_AfterMultipleGuesses() { assertEquals(5, game.getNumGuesses()); } + //tests that correct and incorrect guesses are counted properly @Test void testGetNumGuesses_CountsIncorrectAndCorrectGuesses() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -112,6 +121,7 @@ void testGetNumGuesses_CountsIncorrectAndCorrectGuesses() { // ========== Tests for isDone method ========== + @Test void testIsDone_InitiallyFalse() { HumanGuessesGame game = new HumanGuessesGame(500); @@ -130,6 +140,7 @@ void testIsDone_AfterIncorrectGuess() { @Test void testIsDone_AfterCorrectGuess() { //i think this is a found bug + //game doesn't end properly when a number is guessed correctly HumanGuessesGame game = new HumanGuessesGame(500); game.makeGuess(500); @@ -137,11 +148,7 @@ void testIsDone_AfterCorrectGuess() { assertTrue(game.isDone()); } - - - - - + //test a full binary search scenario of the game logic @Test void testFullGame_BinarySearchPattern() { HumanGuessesGame game = new HumanGuessesGame(750); @@ -155,6 +162,7 @@ void testFullGame_BinarySearchPattern() { assertEquals(4, game.getNumGuesses()); } + //edge case for when the game makes a correct guess on the first try @Test void testGame_GuessOnFirstTry() { HumanGuessesGame game = new HumanGuessesGame(42); @@ -165,7 +173,7 @@ void testGame_GuessOnFirstTry() { assertEquals(1, game.getNumGuesses()); } - + //tests that the upper bound of the game is configured properly @Test void testUpperBound_Value() { assertEquals(1000, HumanGuessesGame.UPPER_BOUND); From 99073200ca408b1bb9d12857b9bcc5cfe216364a Mon Sep 17 00:00:00 2001 From: DavidOlinger <126510514+DavidOlinger@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:20:50 -0500 Subject: [PATCH 07/11] test comments --- test/ComputerGuessesGameTest.java | 27 +++++--- test/GameResultTest.java | 18 ++++-- test/StatsCalculatorTest.java | 102 ++++++++++++------------------ 3 files changed, 73 insertions(+), 74 deletions(-) diff --git a/test/ComputerGuessesGameTest.java b/test/ComputerGuessesGameTest.java index 2e89e34..798b367 100644 --- a/test/ComputerGuessesGameTest.java +++ b/test/ComputerGuessesGameTest.java @@ -82,17 +82,26 @@ void testRecordHigher_IncrementsNumGuesses() { // edge cases - @Test - void testFindingTarget_AtMinBound() { - game.reset(); // 501 - int guess = 501; - while(guess > 1) { - guess = game.recordLower(); - } - assertEquals(1, guess); - } + // This test times out the whole thing, so i commented it out + //The guess never actually gets down to 1 like it should, it just keeps guessing 2 even though + //it says a number from 1-1000, i assume because of the math, it always rounds up + // so it never actually reaches 1 + + + +// @Test +// void testFindingTarget_AtMinBound() { +// game.reset(); // 501 +// int guess = 501; +// +// while(guess > 1) { +// guess = game.recordLower(); +// } +// +// assertEquals(1, guess); +// } @Test void testFindingTarget_AtMaxBound() { diff --git a/test/GameResultTest.java b/test/GameResultTest.java index e7c0d85..0f8711c 100644 --- a/test/GameResultTest.java +++ b/test/GameResultTest.java @@ -1,9 +1,9 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; -/** - * Unit tests for GameResult class - */ + + + public class GameResultTest { // constructor @@ -65,7 +65,6 @@ void testConstructor_ZeroCorrectValue() { @Test void testConstructor_NegativeValues() { - // Edge case - invalid data but class should accept it GameResult result = new GameResult(false, -100, -5); assertEquals(-100, result.correctValue); @@ -114,5 +113,16 @@ void testConstructor_LargeNumberOfGuesses() { assertEquals(1000, result.numGuesses); } + + + + + + + + + + + } diff --git a/test/StatsCalculatorTest.java b/test/StatsCalculatorTest.java index 2e3ccb6..1fed98e 100644 --- a/test/StatsCalculatorTest.java +++ b/test/StatsCalculatorTest.java @@ -7,11 +7,8 @@ */ public class StatsCalculatorTest { - /** - * Test double class that implements GameStats for testing purposes - * This allows us to control the data returned without reading from a file - */ - //using dependency injection + + //Constructor for Dependency INjection private static class TestGameStats extends GameStats { private final int[] gamesPerNumGuesses; private final int maxGuesses; @@ -35,16 +32,18 @@ public int maxNumGuesses() { } } - // ========== Tests for calculateBinCounts ========== + + + + //using dependency injection @Test void testCalculateBinCounts_BasicCase() { - // Create test data: games took 1-10 guesses, with varying counts - // Index 0 = 0 guesses (not used), Index 1 = 1 guess, etc. - int[] gameData = {0, 5, 10, 8, 6, 4, 3, 2, 1, 1, 0}; // 11 elements, max is 10 + + int[] gameData = {0, 5, 10, 8, 6, 4, 3, 2, 1, 1, 0}; TestGameStats stats = new TestGameStats(gameData); - int[] binEdges = {1, 4, 7, 10}; // Bins: 1-4, 4-7, 7-10, 10+ + int[] binEdges = {1, 4, 7, 10}; StatsCalculator calculator = new StatsCalculator(); int[] binCounts = calculator.calculateBinCounts(stats, binEdges); @@ -54,7 +53,7 @@ void testCalculateBinCounts_BasicCase() { @Test void testCalculateBinCounts_EmptyStats() { - int[] gameData = new int[11]; // All zeros + int[] gameData = new int[11]; // All 0s TestGameStats stats = new TestGameStats(gameData); int[] binEdges = {1, 5, 10}; @@ -69,38 +68,28 @@ void testCalculateBinCounts_EmptyStats() { @Test void testCalculateBinCounts_SingleBin() { - int[] gameData = {0, 2, 3, 4, 5, 6}; // 6 elements + int[] gameData = {0, 2, 3, 4, 5, 6}; TestGameStats stats = new TestGameStats(gameData); - int[] binEdges = {1}; // Single bin from 1 to max + int[] binEdges = {1}; // single bin StatsCalculator calculator = new StatsCalculator(); int[] binCounts = calculator.calculateBinCounts(stats, binEdges); assertEquals(1, binCounts.length); - // Should sum all games from index 1 to 5 (maxNumGuesses-1) - // 2 + 3 + 4 + 5 + 6 = 20? But maxNumGuesses is 6, so it goes from 1 to 5 - // 2 + 3 + 4 + 5 = 14 - } - @Test - void testCalculateBinCounts_AllGamesInFirstBin() { - int[] gameData = {0, 10, 5, 0, 0, 0}; // Games only in 1-2 guesses - TestGameStats stats = new TestGameStats(gameData); - int[] binEdges = {1, 3, 5}; - StatsCalculator calculator = new StatsCalculator(); - int[] binCounts = calculator.calculateBinCounts(stats, binEdges); - // First bin (1-3): 10 + 5 + 0 = 15 - // Wait - need to check the algorithm. lowerBound=1, upperBound=3 - // It includes both bounds, so 1, 2, 3 -> 10 + 5 + 0 = 15 } + + + //testing to see if it crashes with weird bins + @Test - void testCalculateBinCounts_AllGamesInLastBin() { - int[] gameData = {0, 0, 0, 0, 0, 5, 10, 8}; // Games only in 5+ guesses + void testCalculateBinCounts_AllGamesInFirstBin() { + int[] gameData = {0, 10, 5, 0, 0, 0}; TestGameStats stats = new TestGameStats(gameData); int[] binEdges = {1, 3, 5}; @@ -108,30 +97,23 @@ void testCalculateBinCounts_AllGamesInLastBin() { int[] binCounts = calculator.calculateBinCounts(stats, binEdges); - // Last bin starts at 5 and goes to maxNumGuesses (8) - // Should sum indices 5, 6, 7 -> 5 + 10 + 8 = 23 + } @Test - void testCalculateBinCounts_VerifyBinBoundaries() { - // Test that bin boundaries work correctly - // Each guess count has exactly 1 game - int[] gameData = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; // 10 games total, indices 1-10 + void testCalculateBinCounts_AllGamesInLastBin() { + int[] gameData = {0, 0, 0, 0, 0, 5, 10, 8}; TestGameStats stats = new TestGameStats(gameData); - int[] binEdges = {1, 4, 7, 10}; + int[] binEdges = {1, 3, 5}; StatsCalculator calculator = new StatsCalculator(); int[] binCounts = calculator.calculateBinCounts(stats, binEdges); - // Bin 0: 1-4 inclusive -> 4 games - // Bin 1: 4-7 inclusive -> 4 games (but 4 is counted in bin 0 too?) - // Need to understand the exact algorithm... - // Looking at code: lowerBound=1, upperBound=4 (from binEdges[1]) - // numGuesses from 1 to 4 inclusive - assertEquals(4, binCounts.length); + } + @Test void testCalculateBinCounts_LargeNumbers() { int[] gameData = new int[101]; // Support up to 100 guesses @@ -147,6 +129,9 @@ void testCalculateBinCounts_LargeNumbers() { assertEquals(3, binCounts.length); } + + + @Test void testCalculateBinCounts_TwoBins() { int[] gameData = {0, 5, 5, 5, 5, 5}; // 5 games per guess count, 1-5 guesses @@ -158,26 +143,11 @@ void testCalculateBinCounts_TwoBins() { int[] binCounts = calculator.calculateBinCounts(stats, binEdges); assertEquals(2, binCounts.length); - // First bin (1-3): 5 + 5 + 5 = 15 - // Second bin (3 to max=6): indices 3, 4, 5 = 5 + 5 + 5 = 15 - } - @Test - void testCalculateBinCounts_NonOverlappingBins() { - // Test with specific known values - int[] gameData = {0, 2, 4, 6, 8, 10, 12}; // indices 0-6 - TestGameStats stats = new TestGameStats(gameData); - int[] binEdges = {1, 3, 5}; - StatsCalculator calculator = new StatsCalculator(); + } - int[] binCounts = calculator.calculateBinCounts(stats, binEdges); - // Bin 0: lowerBound=1, upperBound=3 -> 2+4+6 = 12 - // Bin 1: lowerBound=3, upperBound=5 -> 6+8+10 = 24 - // Bin 2 (last): lowerBound=5 to maxNumGuesses=7 -> indices 5,6 = 10+12 = 22 - assertEquals(3, binCounts.length); - } @Test void testCalculateBinCounts_WithZeroGames() { @@ -189,10 +159,16 @@ void testCalculateBinCounts_WithZeroGames() { int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + assertEquals(2, binCounts.length); + + } - // ========== Edge case tests ========== + + + //EDGE CASES @Test void testCalculateBinCounts_SingleElementBinEdges() { @@ -204,13 +180,17 @@ void testCalculateBinCounts_SingleElementBinEdges() { int[] binCounts = calculator.calculateBinCounts(stats, binEdges); + + assertEquals(1, binCounts.length); - // Last bin from 3 to max (6): 3+4+5 = 12 + + + } @Test void testCalculateBinCounts_MaxGuessesEqualsZero() { - int[] gameData = {}; // Empty data + int[] gameData = {}; //EMPTY TestGameStats stats = new TestGameStats(gameData); int[] binEdges = {1, 5, 10}; From 4e7a55ae6bcad4b9bd2d186a62d67bb8c35bfae6 Mon Sep 17 00:00:00 2001 From: DavidOlinger <126510514+DavidOlinger@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:25:37 -0500 Subject: [PATCH 08/11] updates --- test/StatsRecordParserTest.java | 129 ++++++-------------------------- 1 file changed, 22 insertions(+), 107 deletions(-) diff --git a/test/StatsRecordParserTest.java b/test/StatsRecordParserTest.java index 8f20b50..3e9e407 100644 --- a/test/StatsRecordParserTest.java +++ b/test/StatsRecordParserTest.java @@ -5,6 +5,9 @@ import java.time.LocalDateTime; import java.time.format.DateTimeParseException; + + + /** * Unit tests for StatsRecordParser class * Tests parsing logic and formatting exceptions @@ -18,7 +21,8 @@ void setUp() { parser = new StatsRecordParser(); } - // ========== Tests for parseTimestamp - valid cases ========== + + @Test void testParseTimestamp_ValidFormat() { @@ -43,29 +47,10 @@ void testParseTimestamp_Midnight() { assertEquals(0, result.getMinute()); } - @Test - void testParseTimestamp_EndOfDay() { - String timestampStr = "2026-12-31T23:59:59"; - - LocalDateTime result = parser.parseTimestamp(timestampStr); - - assertEquals(23, result.getHour()); - assertEquals(59, result.getMinute()); - assertEquals(59, result.getSecond()); - } - - @Test - void testParseTimestamp_WithoutSeconds() { - String timestampStr = "2026-02-10T14:30"; - LocalDateTime result = parser.parseTimestamp(timestampStr); - assertEquals(14, result.getHour()); - assertEquals(30, result.getMinute()); - assertEquals(0, result.getSecond()); - } +//invalid tests - // ========== Tests for parseTimestamp - invalid cases (expect exceptions) ========== @Test void testParseTimestamp_InvalidFormat_ThrowsException() { @@ -85,42 +70,9 @@ void testParseTimestamp_EmptyString_ThrowsException() { }); } - @Test - void testParseTimestamp_WrongDateFormat_ThrowsException() { - // US date format instead of ISO - String timestampStr = "02/10/2026 14:30:00"; - assertThrows(DateTimeParseException.class, () -> { - parser.parseTimestamp(timestampStr); - }); - } - @Test - void testParseTimestamp_InvalidMonth_ThrowsException() { - String timestampStr = "2026-13-10T14:30:00"; - assertThrows(DateTimeParseException.class, () -> { - parser.parseTimestamp(timestampStr); - }); - } - - @Test - void testParseTimestamp_InvalidDay_ThrowsException() { - String timestampStr = "2026-02-30T14:30:00"; - - assertThrows(DateTimeParseException.class, () -> { - parser.parseTimestamp(timestampStr); - }); - } - - @Test - void testParseTimestamp_MissingTime_ThrowsException() { - String timestampStr = "2026-02-10"; - - assertThrows(DateTimeParseException.class, () -> { - parser.parseTimestamp(timestampStr); - }); - } @Test void testParseTimestamp_Null_ThrowsException() { @@ -129,7 +81,8 @@ void testParseTimestamp_Null_ThrowsException() { }); } - // ========== Tests for parseNumGuesses - valid cases ========== +//valid tests + @Test void testParseNumGuesses_ValidNumber() { @@ -167,26 +120,17 @@ void testParseNumGuesses_Zero() { assertEquals(0, result); } - @Test - void testParseNumGuesses_NegativeNumber() { - // Should parse negative numbers (even if invalid in context) - String numGuessesStr = "-5"; - int result = parser.parseNumGuesses(numGuessesStr); - assertEquals(-5, result); - } - // ========== Tests for parseNumGuesses - invalid cases (expect exceptions) ========== - @Test - void testParseNumGuesses_NonNumeric_ThrowsException() { - String numGuessesStr = "abc"; - assertThrows(NumberFormatException.class, () -> { - parser.parseNumGuesses(numGuessesStr); - }); - } + + + + + + @Test void testParseNumGuesses_EmptyString_ThrowsException() { @@ -206,15 +150,6 @@ void testParseNumGuesses_Decimal_ThrowsException() { }); } - @Test - void testParseNumGuesses_WithSpaces_ThrowsException() { - String numGuessesStr = " 10 "; - - // Integer.parseInt does not trim whitespace - assertThrows(NumberFormatException.class, () -> { - parser.parseNumGuesses(numGuessesStr); - }); - } @Test void testParseNumGuesses_MixedContent_ThrowsException() { @@ -225,6 +160,9 @@ void testParseNumGuesses_MixedContent_ThrowsException() { }); } + + + @Test void testParseNumGuesses_Null_ThrowsException() { assertThrows(NumberFormatException.class, () -> { @@ -232,11 +170,11 @@ void testParseNumGuesses_Null_ThrowsException() { }); } - // ========== Tests for isWithinDays ========== + + @Test void testIsWithinDays_Recent_ReturnsTrue() { - // A timestamp from 1 day ago should be within 30 days LocalDateTime timestamp = LocalDateTime.now().minusDays(1); assertTrue(parser.isWithinDays(timestamp, 30)); @@ -244,52 +182,29 @@ void testIsWithinDays_Recent_ReturnsTrue() { @Test void testIsWithinDays_Old_ReturnsFalse() { - // A timestamp from 60 days ago should NOT be within 30 days LocalDateTime timestamp = LocalDateTime.now().minusDays(60); assertFalse(parser.isWithinDays(timestamp, 30)); } @Test - void testIsWithinDays_ExactlyAtLimit_ReturnsFalse() { - // A timestamp from exactly 30 days ago should NOT be after the limit - // (it's not AFTER, it's equal to or before) + void testIsWithinDays_Exactly30_ReturnsFalse() { + LocalDateTime timestamp = LocalDateTime.now().minusDays(30); assertFalse(parser.isWithinDays(timestamp, 30)); } - @Test - void testIsWithinDays_JustInsideLimit_ReturnsTrue() { - // A timestamp from just under 30 days ago - LocalDateTime timestamp = LocalDateTime.now().minusDays(29).minusHours(23); - assertTrue(parser.isWithinDays(timestamp, 30)); - } - @Test - void testIsWithinDays_Now_ReturnsTrue() { - LocalDateTime timestamp = LocalDateTime.now(); - - assertTrue(parser.isWithinDays(timestamp, 30)); - } @Test void testIsWithinDays_Future_ReturnsTrue() { - // Future dates should be "within" the past 30 days (they're after the limit) LocalDateTime timestamp = LocalDateTime.now().plusDays(5); assertTrue(parser.isWithinDays(timestamp, 30)); } - @Test - void testIsWithinDays_ZeroDays() { - // With 0 days, only future timestamps should return true - LocalDateTime recent = LocalDateTime.now().minusMinutes(1); - LocalDateTime future = LocalDateTime.now().plusMinutes(1); - - assertFalse(parser.isWithinDays(recent, 0)); - assertTrue(parser.isWithinDays(future, 0)); - } + } From f0a01106c127b65d934840d02615afd21090685c Mon Sep 17 00:00:00 2001 From: Benjamin Smith <122588740+BenSmith1202@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:31:42 -0500 Subject: [PATCH 09/11] Fixed DI for HumanGuessesGame --- src/HumanGuessesGame.java | 10 ++-------- src/HumanGuessesGameMock.java | 13 +++++++++++++ test/HumanGuessesGameTest.java | 32 ++++++++++++++++---------------- 3 files changed, 31 insertions(+), 24 deletions(-) create mode 100644 src/HumanGuessesGameMock.java diff --git a/src/HumanGuessesGame.java b/src/HumanGuessesGame.java index 47b3e54..daafdce 100644 --- a/src/HumanGuessesGame.java +++ b/src/HumanGuessesGame.java @@ -9,7 +9,7 @@ public class HumanGuessesGame { public final static int UPPER_BOUND = 1000; - private final int target; + protected int target; private int numGuesses; private boolean gameIsDone; // true iff makeGuess has been called with the target value @@ -21,13 +21,6 @@ public class HumanGuessesGame { gameIsDone = false; } - // Constructor for testing - allows injecting a specific target value - HumanGuessesGame(int target){ - this.target = target; - numGuesses = 0; - gameIsDone = false; - } - GuessResult makeGuess(int value){ numGuesses += 1; @@ -49,3 +42,4 @@ boolean isDone(){ return gameIsDone; } } + diff --git a/src/HumanGuessesGameMock.java b/src/HumanGuessesGameMock.java new file mode 100644 index 0000000..cd31b83 --- /dev/null +++ b/src/HumanGuessesGameMock.java @@ -0,0 +1,13 @@ +//A Mock version of the game used for testing. +//Allows manually injecting the target number +public class HumanGuessesGameMock extends HumanGuessesGame { + + + // Constructor for testing - allows injecting a specific target value + HumanGuessesGameMock(int target){ + super(); + this.target = target; + } + + +} \ No newline at end of file diff --git a/test/HumanGuessesGameTest.java b/test/HumanGuessesGameTest.java index 2aa157f..831fab6 100644 --- a/test/HumanGuessesGameTest.java +++ b/test/HumanGuessesGameTest.java @@ -12,7 +12,7 @@ public class HumanGuessesGameTest { //Dependency Injection (on HumanGuessesGame) @Test void testMakeGuess_TooLow() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); GuessResult result = game.makeGuess(250); @@ -22,7 +22,7 @@ void testMakeGuess_TooLow() { //ensures that when a guess is too high, the game properly records that result @Test void testMakeGuess_TooHigh() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); GuessResult result = game.makeGuess(750); @@ -32,7 +32,7 @@ void testMakeGuess_TooHigh() { // ensures that proper guesses are recorded @Test void testMakeGuess_Correct() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); GuessResult result = game.makeGuess(500); @@ -42,7 +42,7 @@ void testMakeGuess_Correct() { // checks the edge case where the target is 1 @Test void testMakeGuess_EdgeCase_MinValue() { - HumanGuessesGame game = new HumanGuessesGame(1); + HumanGuessesGame game = new HumanGuessesGameMock(1); assertEquals(GuessResult.CORRECT, game.makeGuess(1)); assertEquals(GuessResult.HIGH, game.makeGuess(2)); @@ -51,7 +51,7 @@ void testMakeGuess_EdgeCase_MinValue() { // checks the egde case when the target is 1000 @Test void testMakeGuess_EdgeCase_MaxValue() { - HumanGuessesGame game = new HumanGuessesGame(1000); + HumanGuessesGame game = new HumanGuessesGameMock(1000); assertEquals(GuessResult.CORRECT, game.makeGuess(1000)); assertEquals(GuessResult.LOW, game.makeGuess(999)); @@ -60,7 +60,7 @@ void testMakeGuess_EdgeCase_MaxValue() { //checks edge case where target is one higher than the guess @Test void testMakeGuess_OneOffLow() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); GuessResult result = game.makeGuess(499); @@ -70,7 +70,7 @@ void testMakeGuess_OneOffLow() { //same but when target is lower @Test void testMakeGuess_OneOffHigh() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); GuessResult result = game.makeGuess(501); @@ -81,7 +81,7 @@ void testMakeGuess_OneOffHigh() { // tests that numGuesses is properly initialized @Test void testGetNumGuesses_InitiallyZero() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); assertEquals(0, game.getNumGuesses()); } @@ -89,7 +89,7 @@ void testGetNumGuesses_InitiallyZero() { //tests that numguesses is incremented @Test void testGetNumGuesses_AfterOneGuess() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); game.makeGuess(250); assertEquals(1, game.getNumGuesses()); @@ -98,7 +98,7 @@ void testGetNumGuesses_AfterOneGuess() { //tests that numguesses is incremented consistently @Test void testGetNumGuesses_AfterMultipleGuesses() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); game.makeGuess(250); game.makeGuess(375); game.makeGuess(437); @@ -111,7 +111,7 @@ void testGetNumGuesses_AfterMultipleGuesses() { //tests that correct and incorrect guesses are counted properly @Test void testGetNumGuesses_CountsIncorrectAndCorrectGuesses() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); game.makeGuess(100); // wrong game.makeGuess(900); // wrong game.makeGuess(500); // correct @@ -124,14 +124,14 @@ void testGetNumGuesses_CountsIncorrectAndCorrectGuesses() { @Test void testIsDone_InitiallyFalse() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); assertFalse(game.isDone()); } @Test void testIsDone_AfterIncorrectGuess() { - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); game.makeGuess(250); assertFalse(game.isDone()); @@ -142,7 +142,7 @@ void testIsDone_AfterCorrectGuess() { //i think this is a found bug //game doesn't end properly when a number is guessed correctly - HumanGuessesGame game = new HumanGuessesGame(500); + HumanGuessesGame game = new HumanGuessesGameMock(500); game.makeGuess(500); assertTrue(game.isDone()); @@ -151,7 +151,7 @@ void testIsDone_AfterCorrectGuess() { //test a full binary search scenario of the game logic @Test void testFullGame_BinarySearchPattern() { - HumanGuessesGame game = new HumanGuessesGame(750); + HumanGuessesGame game = new HumanGuessesGameMock(750); // Simulate binary search assertEquals(GuessResult.LOW, game.makeGuess(500)); @@ -165,7 +165,7 @@ void testFullGame_BinarySearchPattern() { //edge case for when the game makes a correct guess on the first try @Test void testGame_GuessOnFirstTry() { - HumanGuessesGame game = new HumanGuessesGame(42); + HumanGuessesGame game = new HumanGuessesGameMock(42); GuessResult result = game.makeGuess(42); From d6f9d90e72b15795bfc5832a64d9a1e16a902b89 Mon Sep 17 00:00:00 2001 From: Benjamin Smith <122588740+BenSmith1202@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:42:24 -0500 Subject: [PATCH 10/11] updated --- test/StatsCalculatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/StatsCalculatorTest.java b/test/StatsCalculatorTest.java index 1fed98e..97bfe3d 100644 --- a/test/StatsCalculatorTest.java +++ b/test/StatsCalculatorTest.java @@ -8,7 +8,7 @@ public class StatsCalculatorTest { - //Constructor for Dependency INjection + //Mockup for Dependency Injection private static class TestGameStats extends GameStats { private final int[] gamesPerNumGuesses; private final int maxGuesses; From 70eb502b83e471d93a31340e7c46ae34913a946f Mon Sep 17 00:00:00 2001 From: Benjamin Smith <122588740+BenSmith1202@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:43:33 -0500 Subject: [PATCH 11/11] push --- test/README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/README.txt b/test/README.txt index d90cb81..008aaee 100644 --- a/test/README.txt +++ b/test/README.txt @@ -1,7 +1,7 @@ Put your JUnit test classes and test doubles in this folder. Partner Information: -[Add your partner's name here] +Benjamin Smith & David Olinger Test Files: - HumanGuessesGameTest.java - Tests for the human guessing game logic