diff --git a/.github/workflows/check-deprecated-exercises.yml b/.github/workflows/check-deprecated-exercises.yml new file mode 100644 index 000000000..9e39d6af7 --- /dev/null +++ b/.github/workflows/check-deprecated-exercises.yml @@ -0,0 +1,15 @@ +name: Deprecated + +on: + pull_request: + +jobs: + test-deprecated: + name: Check for deprecated exercises + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + with: + fetch-depth: 0 + - name: Test deprecated exercises using test-deprecated-exercises + run: bin/test-deprecated-exercises diff --git a/bin/test-deprecated-exercises b/bin/test-deprecated-exercises new file mode 100755 index 000000000..16e1251e0 --- /dev/null +++ b/bin/test-deprecated-exercises @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -eo pipefail + +# Determine the base branch of the PR +BASE_BRANCH=${GITHUB_BASE_REF:-main} + +# Fetch full history for proper diff +git fetch origin "$BASE_BRANCH" + +# Compute merge base +MERGE_BASE=$(git merge-base HEAD origin/"$BASE_BRANCH") + +# Get changed files relative to merge base +changed_files=$(git diff --name-only "$MERGE_BASE" HEAD) + +# Extract unique exercise directories +changed_exercises=$(echo "$changed_files" | grep -E '^exercises/(practice|concept)/' || true) +changed_exercises=$(echo "$changed_exercises" | cut -d/ -f1-3 | sort -u) + +echo "$changed_exercises" + +if [ -z "$changed_exercises" ]; then + echo "No exercises changed!" + exit 0 +fi + +# Deprecated practice exercises +deprecated_exercises=( + "exercises/practice/accumulate" + "exercises/practice/beer-song" + "exercises/practice/binary" + "exercises/practice/diffie-hellman" + "exercises/practice/hexadecimal" + "exercises/practice/minesweeper" + "exercises/practice/octal" + "exercises/practice/strain" + "exercises/practice/trinary" + "exercises/concept/play-your-cards" +) + +# Check for deprecated ones +for ex in $changed_exercises; do + if printf '%s\n' "${deprecated_exercises[@]}" | grep -qx "$ex"; then + echo "❌ Deprecated exercise changed: $ex" + exit 1 + fi +done + +echo "✅ No deprecated exercises changed!" \ No newline at end of file diff --git a/exercises/practice/anagram/src/test/java/AnagramTest.java b/exercises/practice/anagram/src/test/java/AnagramTest.java index 79a3a261b..c8f9c7421 100644 --- a/exercises/practice/anagram/src/test/java/AnagramTest.java +++ b/exercises/practice/anagram/src/test/java/AnagramTest.java @@ -16,7 +16,7 @@ public void testNoMatches() { assertThat( detector.match( - Arrays.asList("hello", "world", "zombies", "pants"))) + Arrays.asList("helo", "world", "zombies", "pants"))) .isEmpty(); } diff --git a/exercises/practice/nth-prime/src/test/java/PrimeCalculatorTest.java b/exercises/practice/nth-prime/src/test/java/PrimeCalculatorTest.java index e13c7f23d..10d0bcf29 100644 --- a/exercises/practice/nth-prime/src/test/java/PrimeCalculatorTest.java +++ b/exercises/practice/nth-prime/src/test/java/PrimeCalculatorTest.java @@ -1,8 +1,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; public class PrimeCalculatorTest { @@ -10,30 +10,35 @@ public class PrimeCalculatorTest { private PrimeCalculator primeCalculator = new PrimeCalculator(); @Test + @DisplayName("first prime") public void testFirstPrime() { assertThat(primeCalculator.nth(1)).isEqualTo(2); } @Disabled("Remove to run test") @Test + @DisplayName("second prime") public void testSecondPrime() { assertThat(primeCalculator.nth(2)).isEqualTo(3); } @Disabled("Remove to run test") @Test + @DisplayName("sixth prime") public void testSixthPrime() { assertThat(primeCalculator.nth(6)).isEqualTo(13); } @Disabled("Remove to run test") @Test + @DisplayName("big prime") public void testBigPrime() { assertThat(primeCalculator.nth(10001)).isEqualTo(104743); } @Disabled("Remove to run test") @Test + @DisplayName("there is no zeroth prime") public void testUndefinedPrime() { assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> primeCalculator.nth(0)); diff --git a/exercises/practice/nucleotide-count/src/test/java/NucleotideCounterTest.java b/exercises/practice/nucleotide-count/src/test/java/NucleotideCounterTest.java index b47fb836e..d5938268a 100644 --- a/exercises/practice/nucleotide-count/src/test/java/NucleotideCounterTest.java +++ b/exercises/practice/nucleotide-count/src/test/java/NucleotideCounterTest.java @@ -1,4 +1,5 @@ import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.Map; @@ -9,6 +10,7 @@ public class NucleotideCounterTest { @Test + @DisplayName("empty strand") public void testEmptyDnaStringHasNoNucleotides() { NucleotideCounter nucleotideCounter = new NucleotideCounter(""); @@ -19,6 +21,7 @@ public void testEmptyDnaStringHasNoNucleotides() { @Disabled("Remove to run test") @Test + @DisplayName("can count one nucleotide in single-character input") public void testDnaStringHasOneNucleotide() { NucleotideCounter nucleotideCounter = new NucleotideCounter("G"); @@ -29,6 +32,7 @@ public void testDnaStringHasOneNucleotide() { @Disabled("Remove to run test") @Test + @DisplayName("strand with repeated nucleotide") public void testRepetitiveSequenceWithOnlyGuanine() { NucleotideCounter nucleotideCounter = new NucleotideCounter("GGGGGGG"); @@ -39,6 +43,7 @@ public void testRepetitiveSequenceWithOnlyGuanine() { @Disabled("Remove to run test") @Test + @DisplayName("strand with multiple nucleotides") public void testDnaStringHasMultipleNucleotide() { NucleotideCounter nucleotideCounter = new NucleotideCounter("AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC"); @@ -50,6 +55,7 @@ public void testDnaStringHasMultipleNucleotide() { @Disabled("Remove to run test") @Test + @DisplayName("strand with invalid nucleotides") public void testDnaStringHasInvalidNucleotides() { assertThatThrownBy(() -> new NucleotideCounter("AGXXACT")) .isInstanceOf(IllegalArgumentException.class); diff --git a/exercises/practice/ocr-numbers/src/test/java/OpticalCharacterReaderTest.java b/exercises/practice/ocr-numbers/src/test/java/OpticalCharacterReaderTest.java index fbe4c040c..6cc079c23 100644 --- a/exercises/practice/ocr-numbers/src/test/java/OpticalCharacterReaderTest.java +++ b/exercises/practice/ocr-numbers/src/test/java/OpticalCharacterReaderTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -9,6 +10,7 @@ public class OpticalCharacterReaderTest { @Test + @DisplayName("Recognizes 0") public void testReaderRecognizesSingle0() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ ", @@ -23,6 +25,7 @@ public void testReaderRecognizesSingle0() { @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 1") public void testReaderRecognizesSingle1() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " ", @@ -36,6 +39,7 @@ public void testReaderRecognizesSingle1() { @Disabled("Remove to run test") @Test + @DisplayName("Unreadable but correctly sized inputs return ?") public void testReaderReturnsQuestionMarkForUnreadableButCorrectlySizedInput() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " ", @@ -49,6 +53,7 @@ public void testReaderReturnsQuestionMarkForUnreadableButCorrectlySizedInput() { @Disabled("Remove to run test") @Test + @DisplayName("Input with a number of lines that is not a multiple of four raises an error") public void testReaderThrowsExceptionWhenNumberOfInputLinesIsNotAMultipleOf4() { assertThatExceptionOfType(IllegalArgumentException.class) @@ -63,6 +68,7 @@ public void testReaderThrowsExceptionWhenNumberOfInputLinesIsNotAMultipleOf4() { @Disabled("Remove to run test") @Test + @DisplayName("Input with a number of columns that is not a multiple of three raises an error") public void testReaderThrowsExceptionWhenNumberOfInputColumnsIsNotAMultipleOf3() { @@ -79,6 +85,7 @@ public void testReaderThrowsExceptionWhenNumberOfInputColumnsIsNotAMultipleOf3() @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 110101100") public void testReaderRecognizesBinarySequence110101100() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ _ _ _ ", @@ -92,6 +99,7 @@ public void testReaderRecognizesBinarySequence110101100() { @Disabled("Remove to run test") @Test + @DisplayName("Garbled numbers in a string are replaced with ?") public void testReaderReplacesUnreadableDigitsWithQuestionMarksWithinSequence() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ _ _ ", @@ -106,6 +114,7 @@ public void testReaderReplacesUnreadableDigitsWithQuestionMarksWithinSequence() @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 2") public void testReaderRecognizesSingle2() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ ", @@ -119,6 +128,7 @@ public void testReaderRecognizesSingle2() { @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 3") public void testReaderRecognizesSingle3() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ ", @@ -132,6 +142,7 @@ public void testReaderRecognizesSingle3() { @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 4") public void testReaderRecognizesSingle4() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " ", @@ -145,6 +156,7 @@ public void testReaderRecognizesSingle4() { @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 5") public void testReaderRecognizesSingle5() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ ", @@ -158,6 +170,7 @@ public void testReaderRecognizesSingle5() { @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 6") public void testReaderRecognizesSingle6() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ ", @@ -171,6 +184,7 @@ public void testReaderRecognizesSingle6() { @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 7") public void testReaderRecognizesSingle7() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ ", @@ -184,6 +198,7 @@ public void testReaderRecognizesSingle7() { @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 8") public void testReaderRecognizesSingle8() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ ", @@ -197,6 +212,7 @@ public void testReaderRecognizesSingle8() { @Disabled("Remove to run test") @Test + @DisplayName("Recognizes 9") public void testReaderRecognizesSingle9() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ ", @@ -210,6 +226,7 @@ public void testReaderRecognizesSingle9() { @Disabled("Remove to run test") @Test + @DisplayName("Recognizes string of decimal numbers") public void testReaderRecognizesSequence1234567890() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ _ _ _ _ _ _ _ ", @@ -223,6 +240,7 @@ public void testReaderRecognizesSequence1234567890() { @Disabled("Remove to run test") @Test + @DisplayName("Numbers separated by empty lines are recognized. Lines are joined by commas.") public void testReaderRecognizesAndCorrectlyFormatsMultiRowInput() { String parsedInput = new OpticalCharacterReader().parse(Arrays.asList( " _ _ ", diff --git a/exercises/practice/palindrome-products/src/test/java/PalindromeCalculatorTest.java b/exercises/practice/palindrome-products/src/test/java/PalindromeCalculatorTest.java index b82b55109..211b4a9b8 100644 --- a/exercises/practice/palindrome-products/src/test/java/PalindromeCalculatorTest.java +++ b/exercises/practice/palindrome-products/src/test/java/PalindromeCalculatorTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -15,6 +16,7 @@ public class PalindromeCalculatorTest { private PalindromeCalculator palindromeCalculator = new PalindromeCalculator(); @Test + @DisplayName("find the smallest palindrome from single digit factors") public void smallestPalindromeFromSingleDigitFactors() { List> expected = Collections.unmodifiableList( Arrays.asList( @@ -30,6 +32,7 @@ public void smallestPalindromeFromSingleDigitFactors() { @Disabled("Remove to run test") @Test + @DisplayName("find the largest palindrome from single digit factors") public void largestPalindromeFromSingleDigitFactors() { List> expected = Collections.unmodifiableList( Arrays.asList( @@ -46,6 +49,7 @@ public void largestPalindromeFromSingleDigitFactors() { @Disabled("Remove to run test") @Test + @DisplayName("find the smallest palindrome from double digit factors") public void largestPalindromeFromDoubleDigitFactors() { List> expected = Collections.unmodifiableList( Arrays.asList( @@ -62,6 +66,7 @@ public void largestPalindromeFromDoubleDigitFactors() { @Disabled("Remove to run test") @Test + @DisplayName("find the largest palindrome from double digit factors") public void smallestPalindromeFromDoubleDigitFactors() { List> expected = Collections.unmodifiableList( Arrays.asList( @@ -78,6 +83,7 @@ public void smallestPalindromeFromDoubleDigitFactors() { @Disabled("Remove to run test") @Test + @DisplayName("find the largest palindrome from triple digit factors") public void largestPalindromeFromTripleDigitFactors() { List> expected = Collections.unmodifiableList( Arrays.asList( @@ -94,6 +100,7 @@ public void largestPalindromeFromTripleDigitFactors() { @Disabled("Remove to run test") @Test + @DisplayName("find the smallest palindrome from triple digit factors") public void smallestPalindromeFromTripleDigitFactors() { List> expected = Collections.unmodifiableList( Arrays.asList( @@ -110,6 +117,7 @@ public void smallestPalindromeFromTripleDigitFactors() { @Disabled("Remove to run test") @Test + @DisplayName("find the smallest palindrome from four digit factors") public void smallestPalindromeFromQuadDigitFactors() { List> expected = Collections.unmodifiableList( Arrays.asList( @@ -126,6 +134,7 @@ public void smallestPalindromeFromQuadDigitFactors() { @Disabled("Remove to run test") @Test + @DisplayName("find the largest palindrome from four digit factors") public void largestPalindromeFromQuadDigitFactors() { List> expected = Collections.unmodifiableList( Arrays.asList( @@ -142,6 +151,7 @@ public void largestPalindromeFromQuadDigitFactors() { @Disabled("Remove to run test") @Test + @DisplayName("empty result for smallest if no palindrome in the range") public void emtpyResultSmallestNoPalindromeInRange() { SortedMap>> palindromes = palindromeCalculator.getPalindromeProductsWithFactors(1002, @@ -151,6 +161,7 @@ public void emtpyResultSmallestNoPalindromeInRange() { @Disabled("Remove to run test") @Test + @DisplayName("empty result for largest if no palindrome in the range") public void emptyResultLargestNoPalindromeInRange() { SortedMap>> palindromes = palindromeCalculator.getPalindromeProductsWithFactors(15, @@ -160,6 +171,7 @@ public void emptyResultLargestNoPalindromeInRange() { @Disabled("Remove to run test") @Test + @DisplayName("error result for smallest if min is more than max") public void errorSmallestMinIsMoreThanMax() { assertThatExceptionOfType(IllegalArgumentException.class) @@ -169,6 +181,7 @@ public void errorSmallestMinIsMoreThanMax() { @Disabled("Remove to run test") @Test + @DisplayName("error result for largest if min is more than max") public void errorLargestMinIsMoreThanMax() { assertThatExceptionOfType(IllegalArgumentException.class) @@ -178,6 +191,7 @@ public void errorLargestMinIsMoreThanMax() { @Disabled("Remove to run test") @Test + @DisplayName("smallest product does not use the smallest factor") public void smallestProductDoesNotUseTheSmallestFactor() { List> expected = Collections.unmodifiableList( Arrays.asList( diff --git a/exercises/practice/two-bucket/src/main/java/TwoBucket.java b/exercises/practice/two-bucket/src/main/java/TwoBucket.java index 5cd0e4d87..1bc771a94 100644 --- a/exercises/practice/two-bucket/src/main/java/TwoBucket.java +++ b/exercises/practice/two-bucket/src/main/java/TwoBucket.java @@ -1,11 +1,11 @@ class TwoBucket { TwoBucket(int bucketOneCap, int bucketTwoCap, int desiredLiters, String startBucket) { - throw new UnsupportedOperationException("Please implement the TwoBucket(int, int, int, String) constructor."); + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); } Result getResult() { - throw new UnsupportedOperationException("Please implement the TwoBucket(int, int, int, String) constructor."); + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); } }