diff --git a/.github/workflows/check-deprecated-exercises.yml b/.github/workflows/check-deprecated-exercises.yml
new file mode 100644
index 000000000..0f011b79e
--- /dev/null
+++ b/.github/workflows/check-deprecated-exercises.yml
@@ -0,0 +1,21 @@
+name: Deprecated
+
+on:
+ pull_request:
+ paths:
+ - "exercises/**"
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+
+jobs:
+ test-deprecated:
+ name: Check for deprecated exercises
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
+ with:
+ fetch-depth: 0
+ - name: Test deprecated exercises using test-deprecated-exercises
+ run: bin/test-deprecated-exercises
diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml
index 1a4953152..598a68e40 100644
--- a/.github/workflows/java.yml
+++ b/.github/workflows/java.yml
@@ -13,11 +13,11 @@ on:
jobs:
build:
name: Check if tests compile cleanly with starter sources
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Set up JDK 1.17
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00
+ uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e
with:
java-version: 17
distribution: "temurin"
@@ -27,11 +27,11 @@ jobs:
lint:
name: Lint Java files using Checkstyle
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Set up JDK 1.17
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00
+ uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e
with:
java-version: 17
distribution: "temurin"
@@ -39,16 +39,60 @@ jobs:
run: ./gradlew check --exclude-task test --continue
working-directory: exercises
- test:
+ test-all:
name: Test all exercises using java-test-runner
- runs-on: ubuntu-22.04
+ if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
+ runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Test all exercises using java-test-runner
run: bin/test-with-test-runner
+ - name: Print summary
+ run: |
+ if [ -f exercises/build/summary.txt ]; then
+ echo "===== TEST SUMMARY ====="
+ cat exercises/build/summary.txt
+ echo "========================"
+ else
+ echo "===== ALL TESTS PASSED ====="
+ echo "No summary file was generated."
+ echo "============================="
+ fi
+ if: always()
- name: Archive test results
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
with:
name: test-results
path: exercises/**/build/results.json
if: failure()
+
+ test-changed:
+ name: Test changed exercises using gradlew
+ if: github.event_name == 'pull_request'
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
+ with:
+ fetch-depth: 0
+ - name: Test changed exercises using java-test-runner
+ run: bin/test-changed-exercise
+ - name: Print summary
+ run: |
+ if [ -f exercises/build/summary.txt ]; then
+ echo "===== TEST SUMMARY ====="
+ cat exercises/build/summary.txt
+ echo "========================"
+ else
+ echo "===== ALL TESTS PASSED ====="
+ echo "No summary file was generated."
+ echo "============================="
+ fi
+ if: always()
+ - name: Archive test results
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
+ with:
+ name: test-results
+ path: |
+ exercises/**/build/results.txt
+ exercises/**/build/results.json
+ if: failure()
diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml
index 9bcd9dc76..8339bd4db 100644
--- a/.github/workflows/markdown.yml
+++ b/.github/workflows/markdown.yml
@@ -15,8 +15,8 @@ permissions:
jobs:
lint:
name: Lint Markdown files
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Lint markdown
- uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265
+ uses: DavidAnson/markdownlint-cli2-action@07035fd053f7be764496c0f8d8f9f41f98305101
diff --git a/.github/workflows/run-configlet-sync.yml b/.github/workflows/run-configlet-sync.yml
new file mode 100644
index 000000000..b49cbffe8
--- /dev/null
+++ b/.github/workflows/run-configlet-sync.yml
@@ -0,0 +1,10 @@
+name: Run Configlet Sync
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: '0 0 15 * *'
+
+jobs:
+ call-gha-workflow:
+ uses: exercism/github-actions/.github/workflows/configlet-sync.yml@main
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index de4283ca1..56151b2c9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -209,7 +209,7 @@ Each problem/submodule has three source sets:
### Update/sync Gradle versions
-Please read [How to Update Gradle](../reference/how-to-update-gradle.md)
+Please read [How to Update Gradle](reference/how-to-update-gradle.md)
## Contributing to Concept Exercises
diff --git a/POLICIES.md b/POLICIES.md
index 14a857e2a..09d803f04 100644
--- a/POLICIES.md
+++ b/POLICIES.md
@@ -51,7 +51,7 @@ References: [[1](https://github.com/exercism/java/issues/177#issuecomment-261291
> throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
> ```
>
-> - Exercises of difficulty 5 or higher: copy the StubTemplate.java file (provided [here](https://github.com/exercism/java/blob/main/resources/exercise-template/src/main/java/ExerciseName.java)) and rename it to fit the exercise. For example, for the exercise linked-list the file could be named LinkedList.java. Then either (1) add hints to the hints.md file (which gets merged into the README.md for the exercise) or (2) provide stubs as above for exercises that demand complicated method signatures.
+> - Exercises of difficulty 5 or higher: copy the StubTemplate.java file (provided in [this template file](https://github.com/exercism/java/blob/main/resources/exercise-template/src/main/java/ExerciseName.java)) and rename it to fit the exercise. For example, for the exercise linked-list the file could be named LinkedList.java. Then either (1) add hints to the hints.md file (which gets merged into the README.md for the exercise) or (2) provide stubs as above for exercises that demand complicated method signatures.
References: [[1](https://github.com/exercism/java/issues/178)], [[2](https://github.com/exercism/java/pull/683#discussion_r125506930)], [[3](https://github.com/exercism/java/issues/977)], [[4](https://github.com/exercism/java/issues/1721)]
@@ -108,7 +108,7 @@ References: [[1](https://github.com/exercism/java/issues/365#issuecomment-292533
### Good first issues
-> Aim to keep 10-20 small and straightforward issues open at any given time. Identify any such issues by applying the "good first issue" label. You can view the current list of these issues [here](https://github.com/exercism/java/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
+> Aim to keep 10-20 small and straightforward issues open at any given time. Identify any such issues by applying the "good first issue" label. You can view the current list of labeled issues [on GitHub](https://github.com/exercism/java/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
References: [[1](https://github.com/exercism/java/issues/220#issue-196447088)], [[2](https://github.com/exercism/java/issues/1669)]
diff --git a/bin/test-changed-exercise b/bin/test-changed-exercise
new file mode 100755
index 000000000..b18a488e8
--- /dev/null
+++ b/bin/test-changed-exercise
@@ -0,0 +1,78 @@
+#!/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)
+
+# If any Gradle build file changed, run the full suite and exit
+if echo "$changed_files" | grep -qE '\.(gradle|gradlew|bat)$|settings\.gradle'; then
+ echo "Gradle build files changed, running full test suite..."
+ ./bin/test-with-test-runner
+ exit 0
+fi
+
+# Extract unique exercise directories
+changed_exercises=$(echo "$changed_files" | \
+ grep -E '^exercises/(practice|concept)/[^/]+/.+\.java$' | \
+ cut -d/ -f1-3 | sort -u)
+
+if [ -z "$changed_exercises" ]; then
+ echo "No relevant exercises changed, skipping tests."
+ exit 0
+fi
+
+# Print exercises
+echo "Changed exercises detected:"
+echo "$changed_exercises"
+echo "----------------------------------------"
+
+summary_dir="exercises/build"
+summary_file="${summary_dir}/summary.txt"
+mkdir -p "$summary_dir"
+
+# Run tests
+exit_code=0
+for dir in $changed_exercises; do
+ slug=$(basename "$dir")
+
+ echo "========================================"
+ echo "=== Running tests for $slug ==="
+ echo "========================================"
+
+ results_path="$dir/build/results.txt"
+ mkdir -p "$(dirname "$results_path")"
+
+ if [[ $dir == exercises/practice/* ]]; then
+ ./exercises/gradlew -p exercises ":practice:$slug:test" 2>&1 | tee "$results_path" || true
+ elif [[ $dir == exercises/concept/* ]]; then
+ ./exercises/gradlew -p exercises ":concept:$slug:test" 2>&1 | tee "$results_path" || true
+ fi
+
+ # Detect failure
+ if grep -q "FAILED" "$results_path"; then
+ exit_code=1
+
+ # Determine practice/slug or concept/slug
+ relative_path=$(echo "$dir" | sed 's|^exercises/||')
+
+ # Create summary.txt with header only on first failure
+ if [ ! -f "$summary_file" ]; then
+ echo "The following exercises have test failures or test errors:" > "$summary_file"
+ fi
+
+ # Append the correct path (practice/slug or concept/slug)
+ echo "$relative_path" >> "$summary_file"
+ fi
+
+done
+
+exit $exit_code
\ No newline at end of file
diff --git a/bin/test-deprecated-exercises b/bin/test-deprecated-exercises
new file mode 100755
index 000000000..5260d6b6c
--- /dev/null
+++ b/bin/test-deprecated-exercises
@@ -0,0 +1,42 @@
+#!/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)
+
+# Early exit if no exercise changed
+if [ -z "$changed_exercises" ]; then
+ echo "No exercises changed!"
+ exit 0
+fi
+
+# Load deprecated exercises from config.json
+deprecated_exercises=$(jq -r '
+ [
+ (.exercises.concept[]? | select(.status=="deprecated") | "exercises/concept/" + .slug),
+ (.exercises.practice[]? | select(.status=="deprecated") | "exercises/practice/" + .slug)
+ ] | .[]
+' config.json)
+
+# Check for deprecated ones
+for ex in $changed_exercises; do
+ if echo "$deprecated_exercises" | grep -qx "$ex"; then
+ echo "❌ Deprecated exercise changed: $ex"
+ exit 1
+ fi
+done
+
+echo "✅ No deprecated exercises changed!"
diff --git a/bin/test-with-test-runner b/bin/test-with-test-runner
index eed2d74b0..5e5dc8889 100755
--- a/bin/test-with-test-runner
+++ b/bin/test-with-test-runner
@@ -12,6 +12,10 @@ docker pull exercism/java-test-runner
exit_code=0
+summary_dir="exercises/build"
+summary_file="${summary_dir}/summary.txt"
+mkdir -p "$summary_dir"
+
function run_test_runner() {
local slug=$1
local solution_dir=$2
@@ -56,6 +60,18 @@ function verify_exercise() {
if [[ $(jq -r '.status' "${results_file}") != "pass" ]]; then
echo "${slug}: ${implementation_file_key} solution did not pass the tests"
+
+ # Determine practice/slug or concept/slug
+ local relative_path=$(echo "$dir" | sed -E 's|.*/exercises/||')
+
+ # Create summary.txt with header only on first failure
+ if [ ! -f "$summary_file" ]; then
+ echo "The following exercises have test failures or test errors:" > "$summary_file"
+ fi
+
+ # Append the correct path (practice/slug or concept/slug)
+ echo "$relative_path" >> "$summary_file"
+
exit_code=1
fi
diff --git a/concepts/chars/.meta/config.json b/concepts/chars/.meta/config.json
index 7f86b573e..bcf21a72c 100644
--- a/concepts/chars/.meta/config.json
+++ b/concepts/chars/.meta/config.json
@@ -3,5 +3,7 @@
"authors": [
"ystromm"
],
- "contributors": []
+ "contributors": [
+ "kahgoh"
+ ]
}
diff --git a/concepts/chars/about.md b/concepts/chars/about.md
index ff5616166..d6ae4bd75 100644
--- a/concepts/chars/about.md
+++ b/concepts/chars/about.md
@@ -1,6 +1,108 @@
# About
-`char`s are generally easy to use.
-They can be extracted from strings, added back (by means of a string builder), defined and initialised using literals with single quotes, as in `char ch = 'A';`, assigned and compared.
+The Java `char` primitive type is a 16 bit representation of a single Unicode character.
-The Character class encapsulates the char value.
+~~~~exercism/note
+The `char` type is based on the [original Unicode specification][unicode-specification], which used 16 bits to represent characters.
+This is enough to cover most of the common letters and covers characters in the range 0x0000 to 0xFFFF.
+The specification has since expanded the range of possible characters up to 0x01FFFF.
+
+[unicode-specification]: https://www.unicode.org/versions/Unicode1.0.0/
+~~~~
+
+Multiple `char`s can comprise a string, such as `"word"`, or `char`s can be processed independently.
+A `char` literal is surrounded by single quotes (e.g. `'A'`).
+
+```java
+char lowerA = 'a';
+char upperB = 'B';
+```
+
+## Getting the `char`s of a `String`
+
+The `String.toCharArray` method returns a String's chars as an array.
+As mentioned in [arrays][concept-arrays], you can use a `for` loop to iterate over the array.
+
+```java
+String text = "Hello";
+char[] asArray = text.toCharArray();
+
+for (char ch: asArray) {
+ System.out.println(ch);
+}
+
+// Outputs:
+// H
+// e
+// l
+// l
+// o
+```
+
+## The [Character][docs-character] class
+
+There are many builtin library methods to inspect and manipulate `char`s.
+These can be found as static methods of the [`java.lang.Character`][docs-character] class.
+Here are some examples:
+
+```java
+Character.isWhitespace(' '); // true
+Character.isWhitespace('#'); // false
+
+Character.isLetter('a'); // true
+Character.isLetter('3'); // false
+
+Character.isDigit('6'); // true
+Character.isDigit('?'); // false
+```
+
+~~~~exercism/note
+Some methods in the Character class have an overload so that it can take either an `char` or `int`.
+For example, `isDigit` has one that accepts a [`char`][is-digit-char] and another an [`int`][is-digit-int].
+As mentioned earlier, the `char` type can only represent the characters in the range from 0x0000 to 0xFFFF.
+The `int`, however, can represent all characters, hence the `int` overloads.
+
+[is-digit-char]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Character.html#isDigit(char)
+[is-digit-int]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Character.html#isDigit(int)
+~~~~
+
+## Adding a `char` to a `String`
+
+The `+` operator can be used to add a `char` to a `String`.
+
+```java
+'a' + " banana" // => "a banana"
+"banana " + 'a' // => "banana a"
+```
+
+~~~~exercism/caution
+Becareful _not_ to use `+` to join two `char`s together to form a `String`!
+Adding two `char`s this way gives an `int`, _not_ a `String`!
+For example:
+
+```java
+'b' + 'c';
+// => 197 (not the String "bc")
+```
+
+This is because Java promotes the `char` to an `int` (see [4.2 Primitive Types and Values ][jls-primitives] of the [Java Language Specification][jls-main]).
+
+[jls-main]: https://docs.oracle.com/javase/specs/jls/se21/html/
+[jls-primitives]: https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html#jls-4.2
+~~~~
+
+However, when there are many characters to be added, it can be more efficient to use a [`StringBuilder`][docs-stringBuilder] instead:
+
+```java
+StringBuilder builder = new StringBuilder();
+builder.append('a');
+builder.append('b');
+builder.append('c');
+
+String builtString = builder.toString();
+// => abc
+```
+
+[concept-arrays]: https://exercism.org/tracks/java/concepts/arrays
+[docs-character]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Character.html
+[docs-stringBuilder]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/StringBuilder.html
diff --git a/concepts/chars/introduction.md b/concepts/chars/introduction.md
index 12fdaf086..bb80baba7 100644
--- a/concepts/chars/introduction.md
+++ b/concepts/chars/introduction.md
@@ -1,12 +1,87 @@
# Introduction
-The Java `char` type represents the smallest addressable components of text.
-Multiple `char`s can comprise a string such as `"word"` or `char`s can be processed independently.
-Their literals have single quotes e.g. `'A'`.
+## chars
+
+The Java `char` primitive type is a 16 bit representation of a single character.
+Multiple `char`s can comprise a string, such as `"word"`, or `char`s can be processed independently.
+A `char` literal is surrounded by single quotes (e.g. `'A'`).
+
+```java
+char lowerA = 'a';
+char upperB = 'B';
+```
+
+## Getting the `char`s of a `String`
+
+The `String.toCharArray` method returns a String's chars as an array.
+As mentioned in arrays, you can use a `for` loop to iterate over the array.
+
+```java
+String text = "Hello";
+char[] asArray = text.toCharArray();
+
+for (char ch: asArray) {
+ System.out.println(ch);
+}
+
+// Outputs:
+// H
+// e
+// l
+// l
+// o
+```
+
+## The Character class
There are many builtin library methods to inspect and manipulate `char`s.
These can be found as static methods of the `java.lang.Character` class.
+Here are some examples:
+
+```java
+Character.isWhitespace(' '); // true
+Character.isWhitespace('#'); // false
+
+Character.isLetter('a'); // true
+Character.isLetter('3'); // false
+
+Character.isDigit('6'); // true
+Character.isDigit('?'); // false
+```
+
+## Adding a `char` to a `String`
+
+The `+` operator can be used to add a `char` to a `String`.
+
+```java
+'a' + " banana" // => "a banana"
+"banana " + 'a' // => "banana a"
+```
+
+~~~~exercism/caution
+Becareful _not_ to use `+` to join two `char`s together to form a `String`!
+Adding two `char`s this way gives an `int`, _not_ a `String`!
+For example:
+
+```java
+'b' + 'c';
+// => 197 (not the String "bc")
+```
+
+This is because Java promotes the `char` to an `int` (see [4.2 Primitive Types and Values ][jls-primitives] of the [Java Language Specification][jls-main]).
+
+[jls-main]: https://docs.oracle.com/javase/specs/jls/se21/html/
+[jls-primitives]: https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html#jls-4.2
+~~~~
+
+However, when there are many characters to be added, it can be more efficient to use a `StringBuilder` instead:
+
+```java
+StringBuilder builder = new StringBuilder();
+builder.append('a');
+builder.append('b');
+builder.append('c');
-`char`s are sometimes used in conjunction with a `StringBuilder` object.
-This object has methods that allow a string to be constructed character by character and manipulated.
-At the end of the process `toString` can be called on it to output a complete string.
+String builtString = builder.toString();
+// => abc
+```
diff --git a/concepts/chars/links.json b/concepts/chars/links.json
index bf2b4a182..b78281499 100644
--- a/concepts/chars/links.json
+++ b/concepts/chars/links.json
@@ -1,12 +1,10 @@
[
{
- "url":"https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html",
+ "url":"https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Character.html",
"description":"javadoc"
},
{
- "url": "https://docs.oracle.com/javase/tutorial/i18n/text/unicode.html",
- "description": "unicode"
+ "url": "https://dev.java/learn/numbers-strings/characters/",
+ "description": "characters"
}
-
-
]
diff --git a/concepts/classes/introduction.md b/concepts/classes/introduction.md
index 7a488babe..08c04a5aa 100644
--- a/concepts/classes/introduction.md
+++ b/concepts/classes/introduction.md
@@ -33,7 +33,7 @@ class Car {
```
One can optionally assign an initial value to a field.
-If a field does _not_ specify an initial value, it wll be set to its type's default value.
+If a field does _not_ specify an initial value, it will be set to its type's default value.
An instance's field values can be accessed and updated using dot-notation.
```java
diff --git a/concepts/datetime/about.md b/concepts/datetime/about.md
index 2724d5cdb..8ab1fbad6 100644
--- a/concepts/datetime/about.md
+++ b/concepts/datetime/about.md
@@ -47,13 +47,13 @@ These methods return a _new_ `LocalDate` instance and do not update the existing
```java
LocalDate date = LocalDate.of(2007, 12, 3);
-date.addDays(3);
+date.plusDays(3);
// => 2007-12-06
-date.addMonths(1);
+date.plusMonths(1);
// => 2008-01-03
-date.addYears(1);
+date.plusYears(1);
// => 2008-12-03
```
diff --git a/concepts/datetime/introduction.md b/concepts/datetime/introduction.md
index afb15b114..2b9513189 100644
--- a/concepts/datetime/introduction.md
+++ b/concepts/datetime/introduction.md
@@ -41,7 +41,7 @@ These methods return a _new_ `LocalDate` instance and do not update the existing
```java
LocalDate date = LocalDate.of(2007, 12, 3);
-date.addDays(3);
+date.plusDays(3);
// => 2007-12-06
```
diff --git a/concepts/exceptions/.meta/config.json b/concepts/exceptions/.meta/config.json
index 1c6bc8bb3..ef26a0098 100644
--- a/concepts/exceptions/.meta/config.json
+++ b/concepts/exceptions/.meta/config.json
@@ -1,5 +1,5 @@
{
"blurb": "Exceptions are thrown when an error that needs special handling occurs.",
"authors": ["sanderploegsma"],
- "contributors": []
+ "contributors": ["BahaaMohamed98"]
}
diff --git a/concepts/exceptions/about.md b/concepts/exceptions/about.md
index 96e2bc4a5..d3a4f5946 100644
--- a/concepts/exceptions/about.md
+++ b/concepts/exceptions/about.md
@@ -8,11 +8,12 @@ An exception is an event that occurs during the execution of a program that disr
Exceptions are raised explicitly in Java, and the act of raising an exception is called _throwing an exception_.
The act of handling an exception is called _catching an exception_.
-Java distinguishes three types of exceptions:
+In Java, all exceptions are subclasses of the `Exception` class, which itself is a subclass of `Throwable`.
+
+Java distinguishes two types of exceptions:
1. Checked exceptions
2. Unchecked exceptions
-3. Errors
### Checked exceptions
@@ -21,7 +22,7 @@ An example of a checked exception is the `FileNotFoundException` which occurs wh
This type of exception is checked at compile-time: methods that throw checked exceptions should specify this in their method signature, and code calling a method that might throw a checked exception is required to handle it or the code will not compile.
-All exceptions in Java that do not inherit from `RuntimeException` or `Error` are considered checked exceptions.
+All checked exceptions are subclasses of `Exception` that do not extend `RuntimeException`.
### Unchecked exceptions
@@ -30,17 +31,7 @@ An example of an unchecked exception is the `NullPointerException` which occurs
This type of exception is not checked at compile-time: methods that throw unchecked exceptions are not required to specify this in their method signature, and code calling a method that might throw an unchecked exception is not required to handle it.
-All exceptions in Java that inherit from `RuntimeException` are considered unchecked exceptions.
-
-### Errors
-
-_Errors_ are exceptional conditions that are external to an application.
-An example of an error is the `OutOfMemoryError` which occurs when an application is trying to use more memory than is available on the system.
-
-Like unchecked exceptions, errors are not checked at compile-time.
-They are not usually thrown from application code.
-
-All exceptions in Java that inherit from `Error` are considered errors.
+All unchecked exceptions inherit from `RuntimeException`, which itself is an extension of `Exception`.
## Throwing exceptions
@@ -135,6 +126,17 @@ Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0
```
+## Errors
+
+Java also has a separate category called _Errors_ which are serious problems that are external to an application.
+An example of an error is the `OutOfMemoryError` which occurs when an application is trying to use more memory than is available on the system.
+
+Like unchecked exceptions, errors are not checked at compile-time.
+The difference is that they represent system level problems and are generally thrown by the Java Virtual machine or environment instead of the application.
+Applications should generally not attempt to catch or handle them.
+
+All errors in Java inherit from the `Error` class.
+
## When not to use exceptions
As stated previously, exceptions are events that disrupt the normal flow of instructions, and are used to handle _exceptional events_.
diff --git a/concepts/exceptions/introduction.md b/concepts/exceptions/introduction.md
index 586f6f1ea..c50113113 100644
--- a/concepts/exceptions/introduction.md
+++ b/concepts/exceptions/introduction.md
@@ -8,11 +8,12 @@ An exception is an event that occurs during the execution of a program that disr
Exceptions are raised explicitly in Java, and the act of raising an exception is called _throwing an exception_.
The act of handling an exception is called _catching an exception_.
-Java distinguishes three types of exceptions:
+In Java, all exceptions are subclasses of the `Exception` class, which itself is a subclass of `Throwable`.
+
+Java distinguishes two types of exceptions:
1. Checked exceptions
2. Unchecked exceptions
-3. Errors
### Checked exceptions
@@ -21,7 +22,7 @@ An example of a checked exception is the `FileNotFoundException` which occurs wh
This type of exception is checked at compile-time: methods that throw checked exceptions should specify this in their method signature, and code calling a method that might throw a checked exception is required to handle it or the code will not compile.
-All exceptions in Java that do not inherit from `RuntimeException` or `Error` are considered checked exceptions.
+All checked exceptions are subclasses of `Exception` that do not extend `RuntimeException`.
### Unchecked exceptions
@@ -30,17 +31,7 @@ An example of an unchecked exception is the `NullPointerException` which occurs
This type of exception is not checked at compile-time: methods that throw unchecked exceptions are not required to specify this in their method signature, and code calling a method that might throw an unchecked exception is not required to handle it.
-All exceptions in Java that inherit from `RuntimeException` are considered unchecked exceptions.
-
-### Errors
-
-_Errors_ are exceptional conditions that are external to an application.
-An example of an error is the `OutOfMemoryError` which occurs when an application is trying to use more memory than is available on the system.
-
-Like unchecked exceptions, errors are not checked at compile-time.
-They are not usually thrown from application code.
-
-All exceptions in Java that inherit from `Error` are considered errors.
+All unchecked exceptions inherit from `RuntimeException`, which itself is an extension of `Exception`.
## Throwing exceptions
@@ -134,3 +125,14 @@ Withdrawing -10.0
Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0
```
+
+## Errors
+
+Java also has a separate category called _Errors_ which are serious problems that are external to an application.
+An example of an error is the `OutOfMemoryError` which occurs when an application is trying to use more memory than is available on the system.
+
+Like unchecked exceptions, errors are not checked at compile-time.
+The difference is that they represent system level problems and are generally thrown by the Java Virtual machine or environment instead of the application.
+Applications should generally not attempt to catch or handle them.
+
+All errors in Java inherit from the `Error` class.
diff --git a/concepts/inheritance/about.md b/concepts/inheritance/about.md
index 4d1698bb8..bd6dd590e 100644
--- a/concepts/inheritance/about.md
+++ b/concepts/inheritance/about.md
@@ -18,7 +18,7 @@ There are four access modifiers:
- `protected`
- default (No keyword required)
-You can read more about them [here][access-modifiers]
+You can read more about them [in this article][access-modifiers]
## Inheritance vs Composition
diff --git a/concepts/switch-statement/about.md b/concepts/switch-statement/about.md
index 9d53f54cb..2c89c5c04 100644
--- a/concepts/switch-statement/about.md
+++ b/concepts/switch-statement/about.md
@@ -145,7 +145,7 @@ Starting with Java 14 (available as a preview before in Java 12 and 13) it is po
However if you use the new `->` notation it must be followed by either: a single statement/expression, a `throw` statement or a `{}` block.
No more confusion!
-You can find more information on enhanced switch [here][switch1], [here][switch2] and on the [oracle documentation][oracle-doc].
+You can find more information on enhanced switch in [this article][switch1] and [this one][switch2], along with the official [Oracle documentation][oracle-doc].
In addition, a feature called `Guarded Patterns` was added in Java 21, which allows you to do checks in the case label itself.
@@ -160,7 +160,7 @@ return switch (day) {
};
```
-You can find more information on the switch expression on Java 21 [here][switch-on-Java-21]
+You can find more information on the switch expression on Java 21 in [this blog][switch-on-Java-21]
[yield-keyword]: https://www.codejava.net/java-core/the-java-language/yield-keyword-in-java
[switch1]: https://www.vojtechruzicka.com/java-enhanced-switch/
diff --git a/config.json b/config.json
index 7c8f6b933..92dfd05b1 100644
--- a/config.json
+++ b/config.json
@@ -105,6 +105,7 @@
"chars"
],
"prerequisites": [
+ "arrays",
"strings"
],
"status": "active"
@@ -809,6 +810,16 @@
],
"difficulty": 4
},
+ {
+ "slug": "rate-limiter",
+ "name": "Rate Limiter",
+ "uuid": "b4b0c60e-4ce1-488e-948f-bcb6821c773c",
+ "practices": [],
+ "prerequisites": [
+ "generic-types"
+ ],
+ "difficulty": 4
+ },
{
"slug": "rotational-cipher",
"name": "Rotational Cipher",
@@ -842,6 +853,17 @@
],
"difficulty": 4
},
+ {
+ "slug": "split-second-stopwatch",
+ "name": "Split-Second Stopwatch",
+ "uuid": "9510c0ae-9977-4260-8991-0e8e849094b0",
+ "practices": [],
+ "prerequisites": [
+ "exceptions",
+ "if-else-statements"
+ ],
+ "difficulty": 4
+ },
{
"slug": "sum-of-multiples",
"name": "Sum of Multiples",
@@ -854,6 +876,18 @@
],
"difficulty": 4
},
+ {
+ "slug": "swift-scheduling",
+ "name": "Swift Scheduling",
+ "uuid": "7f5388dc-ce0e-40d4-98d1-7a00aeae018d",
+ "practices": [],
+ "prerequisites": [
+ "if-else-statements",
+ "datetime",
+ "strings"
+ ],
+ "difficulty": 4
+ },
{
"slug": "triangle",
"name": "Triangle",
@@ -1054,6 +1088,19 @@
],
"difficulty": 5
},
+ {
+ "slug": "relative-distance",
+ "name": "Relative Distance",
+ "uuid": "a3cf95fd-c7c1-4199-a253-7bae8d1aba9a",
+ "practices": [
+ "maps"
+ ],
+ "prerequisites": [
+ "lists",
+ "maps"
+ ],
+ "difficulty": 5
+ },
{
"slug": "robot-name",
"name": "Robot Name",
@@ -1164,6 +1211,20 @@
],
"difficulty": 6
},
+ {
+ "slug": "baffling-birthdays",
+ "name": "Baffling Birthdays",
+ "uuid": "b534049a-5920-4906-9091-0fa6d81a3636",
+ "practices": [],
+ "prerequisites": [
+ "for-loops",
+ "lists",
+ "sets",
+ "randomness",
+ "datetime"
+ ],
+ "difficulty": 6
+ },
{
"slug": "bank-account",
"name": "Bank Account",
@@ -1226,6 +1287,18 @@
],
"difficulty": 6
},
+ {
+ "slug": "flower-field",
+ "name": "Flower Field",
+ "uuid": "bddd180a-d634-454a-af03-4d625f77e1e2",
+ "practices": [],
+ "prerequisites": [
+ "constructors",
+ "lists",
+ "strings"
+ ],
+ "difficulty": 6
+ },
{
"slug": "food-chain",
"name": "Food Chain",
@@ -1259,6 +1332,14 @@
],
"difficulty": 6
},
+ {
+ "slug": "intergalactic-transmission",
+ "name": "Intergalactic Transmission",
+ "uuid": "b1c6dfc2-414b-45b2-9277-8b9f8bb3bcf3",
+ "practices": [],
+ "prerequisites": [],
+ "difficulty": 6
+ },
{
"slug": "linked-list",
"name": "Linked List",
@@ -1276,12 +1357,9 @@
"name": "Minesweeper",
"uuid": "416a1489-12af-4593-8540-0f55285c96b4",
"practices": [],
- "prerequisites": [
- "constructors",
- "lists",
- "strings"
- ],
- "difficulty": 6
+ "prerequisites": [],
+ "difficulty": 6,
+ "status": "deprecated"
},
{
"slug": "parallel-letter-frequency",
@@ -1294,6 +1372,18 @@
],
"difficulty": 6
},
+ {
+ "slug": "piecing-it-together",
+ "name": "Piecing It Together",
+ "uuid": "be303729-ad8a-4f4c-a235-6828a6734f05",
+ "practices": [],
+ "prerequisites": [
+ "exceptions",
+ "for-loops",
+ "if-else-statements"
+ ],
+ "difficulty": 6
+ },
{
"slug": "queen-attack",
"name": "Queen Attack",
diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md
index 239409351..57cf6d012 100644
--- a/docs/INSTALLATION.md
+++ b/docs/INSTALLATION.md
@@ -9,7 +9,7 @@ Here at Exercism we recommend using [Eclipse Temurin by Adoptium][adoptium].
## Supported Java versions
-Exercism's Java track supports Java 21 LTS and earlier.
+Exercism's Java track supports Java 25 LTS and earlier.
## Installing Eclipse Temurin
diff --git a/exercises/build.gradle b/exercises/build.gradle
index 734815214..c35dc4fc1 100644
--- a/exercises/build.gradle
+++ b/exercises/build.gradle
@@ -79,7 +79,7 @@ subprojects {
// configuration of the linter
checkstyle {
toolVersion '10.7.0'
- configFile file("checkstyle.xml")
+ configFile file("$rootDir/checkstyle.xml")
sourceSets = [project.sourceSets.main, project.sourceSets.test]
}
diff --git a/exercises/checkstyle.xml b/exercises/checkstyle.xml
index aee09b5d8..8746c0e28 100644
--- a/exercises/checkstyle.xml
+++ b/exercises/checkstyle.xml
@@ -155,7 +155,7 @@ page at http://checkstyle.sourceforge.net/config.html -->
-
+
diff --git a/exercises/concept/annalyns-infiltration/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/annalyns-infiltration/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/annalyns-infiltration/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/annalyns-infiltration/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/annalyns-infiltration/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/annalyns-infiltration/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/annalyns-infiltration/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/annalyns-infiltration/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/annalyns-infiltration/gradlew b/exercises/concept/annalyns-infiltration/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/annalyns-infiltration/gradlew
+++ b/exercises/concept/annalyns-infiltration/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/annalyns-infiltration/gradlew.bat b/exercises/concept/annalyns-infiltration/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/annalyns-infiltration/gradlew.bat
+++ b/exercises/concept/annalyns-infiltration/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/annalyns-infiltration/src/test/java/AnnalynsInfiltrationTest.java b/exercises/concept/annalyns-infiltration/src/test/java/AnnalynsInfiltrationTest.java
index 4f7fe3864..7514451bf 100644
--- a/exercises/concept/annalyns-infiltration/src/test/java/AnnalynsInfiltrationTest.java
+++ b/exercises/concept/annalyns-infiltration/src/test/java/AnnalynsInfiltrationTest.java
@@ -9,7 +9,7 @@ public class AnnalynsInfiltrationTest {
@Test
@Tag("task:1")
@DisplayName("The canFastAttack method returns false when knight is awake")
- public void cannot_execute_fast_attack_if_knight_is_awake() {
+ public void cannotExecuteFastAttackIfKnightIsAwake() {
boolean knightIsAwake = true;
assertThat(AnnalynsInfiltration.canFastAttack(knightIsAwake)).isFalse();
}
@@ -17,7 +17,7 @@ public void cannot_execute_fast_attack_if_knight_is_awake() {
@Test
@Tag("task:1")
@DisplayName("The canFastAttack method returns true when knight is sleeping")
- public void can_execute_fast_attack_if_knight_is_sleeping() {
+ public void canExecuteFastAttackIfKnightIsSleeping() {
boolean knightIsAwake = false;
assertThat(AnnalynsInfiltration.canFastAttack(knightIsAwake)).isTrue();
}
@@ -25,7 +25,7 @@ public void can_execute_fast_attack_if_knight_is_sleeping() {
@Test
@Tag("task:2")
@DisplayName("The canSpy method returns false when everyone is sleeping")
- public void cannot_spy_if_everyone_is_sleeping() {
+ public void cannotSpyIfEveryoneIsSleeping() {
boolean knightIsAwake = false;
boolean archerIsAwake = false;
boolean prisonerIsAwake = false;
@@ -35,7 +35,7 @@ public void cannot_spy_if_everyone_is_sleeping() {
@Test
@Tag("task:2")
@DisplayName("The canSpy method returns true when everyone but knight is sleeping")
- public void can_spy_if_everyone_but_knight_is_sleeping() {
+ public void canSpyIfEveryoneButKnightIsSleeping() {
boolean knightIsAwake = true;
boolean archerIsAwake = false;
boolean prisonerIsAwake = false;
@@ -45,7 +45,7 @@ public void can_spy_if_everyone_but_knight_is_sleeping() {
@Test
@Tag("task:2")
@DisplayName("The canSpy method returns true when everyone but archer is sleeping")
- public void can_spy_if_everyone_but_archer_is_sleeping() {
+ public void canSpyIfEveryoneButArcherIsSleeping() {
boolean knightIsAwake = false;
boolean archerIsAwake = true;
boolean prisonerIsAwake = false;
@@ -55,7 +55,7 @@ public void can_spy_if_everyone_but_archer_is_sleeping() {
@Test
@Tag("task:2")
@DisplayName("The canSpy method returns true when everyone but prisoner is sleeping")
- public void can_spy_if_everyone_but_prisoner_is_sleeping() {
+ public void canSpyIfEveryoneButPrisonerIsSleeping() {
boolean knightIsAwake = false;
boolean archerIsAwake = false;
boolean prisonerIsAwake = true;
@@ -65,7 +65,7 @@ public void can_spy_if_everyone_but_prisoner_is_sleeping() {
@Test
@Tag("task:2")
@DisplayName("The canSpy method returns true when only knight is sleeping")
- public void can_spy_if_only_knight_is_sleeping() {
+ public void canSpyIfOnlyKnightIsSleeping() {
boolean knightIsAwake = false;
boolean archerIsAwake = true;
boolean prisonerIsAwake = true;
@@ -75,7 +75,7 @@ public void can_spy_if_only_knight_is_sleeping() {
@Test
@Tag("task:2")
@DisplayName("The canSpy method returns true when only archer is sleeping")
- public void can_spy_if_only_archer_is_sleeping() {
+ public void canSpyIfOnlyArcherIsSleeping() {
boolean knightIsAwake = true;
boolean archerIsAwake = false;
boolean prisonerIsAwake = true;
@@ -85,7 +85,7 @@ public void can_spy_if_only_archer_is_sleeping() {
@Test
@Tag("task:2")
@DisplayName("The canSpy method returns true when only prisoner is sleeping")
- public void can_spy_if_only_prisoner_is_sleeping() {
+ public void canSpyIfOnlyPrisonerIsSleeping() {
boolean knightIsAwake = true;
boolean archerIsAwake = true;
boolean prisonerIsAwake = false;
@@ -95,7 +95,7 @@ public void can_spy_if_only_prisoner_is_sleeping() {
@Test
@Tag("task:2")
@DisplayName("The canSpy method returns true when everyone is awake")
- public void can_spy_if_everyone_is_awake() {
+ public void canSpyIfEveryoneIsAwake() {
boolean knightIsAwake = true;
boolean archerIsAwake = true;
boolean prisonerIsAwake = true;
@@ -105,7 +105,7 @@ public void can_spy_if_everyone_is_awake() {
@Test
@Tag("task:3")
@DisplayName("The canSignalPrisoner method returns true when prisoner is awake and archer is sleeping")
- public void can_signal_prisoner_if_archer_is_sleeping_and_prisoner_is_awake() {
+ public void canSignalPrisonerIfArcherIsSleepingAndPrisonerIsAwake() {
boolean archerIsAwake = false;
boolean prisonerIsAwake = true;
assertThat(AnnalynsInfiltration.canSignalPrisoner(archerIsAwake, prisonerIsAwake)).isTrue();
@@ -114,7 +114,7 @@ public void can_signal_prisoner_if_archer_is_sleeping_and_prisoner_is_awake() {
@Test
@Tag("task:3")
@DisplayName("The canSignalPrisoner method returns false when prisoner is sleeping and archer is awake")
- public void cannot_signal_prisoner_if_archer_is_awake_and_prisoner_is_sleeping() {
+ public void cannotSignalPrisonerIfArcherIsAwakeAndPrisonerIsSleeping() {
boolean archerIsAwake = true;
boolean prisonerIsAwake = false;
assertThat(AnnalynsInfiltration.canSignalPrisoner(archerIsAwake, prisonerIsAwake)).isFalse();
@@ -123,7 +123,7 @@ public void cannot_signal_prisoner_if_archer_is_awake_and_prisoner_is_sleeping()
@Test
@Tag("task:3")
@DisplayName("The canSignalPrisoner method returns false when both prisoner and archer are sleeping")
- public void cannot_signal_prisoner_if_archer_and_prisoner_are_both_sleeping() {
+ public void cannotSignalPrisonerIfArcherAndPrisonerAreBothSleeping() {
boolean archerIsAwake = false;
boolean prisonerIsAwake = false;
assertThat(AnnalynsInfiltration.canSignalPrisoner(archerIsAwake, prisonerIsAwake)).isFalse();
@@ -132,7 +132,7 @@ public void cannot_signal_prisoner_if_archer_and_prisoner_are_both_sleeping() {
@Test
@Tag("task:3")
@DisplayName("The canSignalPrisoner method returns false when both prisoner and archer are awake")
- public void cannot_signal_prisoner_if_archer_and_prisoner_are_both_awake() {
+ public void cannotSignalPrisonerIfArcherAndPrisonerAreBothAwake() {
boolean archerIsAwake = true;
boolean prisonerIsAwake = true;
assertThat(AnnalynsInfiltration.canSignalPrisoner(archerIsAwake, prisonerIsAwake)).isFalse();
@@ -141,7 +141,7 @@ public void cannot_signal_prisoner_if_archer_and_prisoner_are_both_awake() {
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when everyone is awake and pet dog is present")
- public void cannot_release_prisoner_if_everyone_is_awake_and_pet_dog_is_present() {
+ public void cannotReleasePrisonerIfEveryoneIsAwakeAndPetDogIsPresent() {
boolean knightIsAwake = true;
boolean archerIsAwake = true;
boolean prisonerIsAwake = true;
@@ -153,7 +153,7 @@ public void cannot_release_prisoner_if_everyone_is_awake_and_pet_dog_is_present(
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when everyone is awake and pet dog is absent")
- public void cannot_release_prisoner_if_everyone_is_awake_and_pet_dog_is_absent() {
+ public void cannotReleasePrisonerIfEveryoneIsAwakeAndPetDogIsAbsent() {
boolean knightIsAwake = true;
boolean archerIsAwake = true;
boolean prisonerIsAwake = true;
@@ -165,7 +165,7 @@ public void cannot_release_prisoner_if_everyone_is_awake_and_pet_dog_is_absent()
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns true when everyone is sleeping and pet dog is present")
- public void can_release_prisoner_if_everyone_is_asleep_and_pet_dog_is_present() {
+ public void canReleasePrisonerIfEveryoneIsAsleepAndPetDogIsPresent() {
boolean knightIsAwake = false;
boolean archerIsAwake = false;
boolean prisonerIsAwake = false;
@@ -177,7 +177,7 @@ public void can_release_prisoner_if_everyone_is_asleep_and_pet_dog_is_present()
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when everyone is sleeping and pet dog is absent")
- public void cannot_release_prisoner_if_everyone_is_asleep_and_pet_dog_is_absent() {
+ public void cannotReleasePrisonerIfEveryoneIsAsleepAndPetDogIsAbsent() {
boolean knightIsAwake = false;
boolean archerIsAwake = false;
boolean prisonerIsAwake = false;
@@ -189,7 +189,7 @@ public void cannot_release_prisoner_if_everyone_is_asleep_and_pet_dog_is_absent(
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns true when only prisoner is awake and pet dog is present")
- public void can_release_prisoner_if_only_prisoner_is_awake_and_pet_dog_is_present() {
+ public void canReleasePrisonerIfOnlyPrisonerIsAwakeAndPetDogIsPresent() {
boolean knightIsAwake = false;
boolean archerIsAwake = false;
boolean prisonerIsAwake = true;
@@ -201,7 +201,7 @@ public void can_release_prisoner_if_only_prisoner_is_awake_and_pet_dog_is_presen
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns true when only prisoner is awake and pet dog is absent")
- public void can_release_prisoner_if_only_prisoner_is_awake_and_pet_dog_is_absent() {
+ public void canReleasePrisonerIfOnlyPrisonerIsAwakeAndPetDogIsAbsent() {
boolean knightIsAwake = false;
boolean archerIsAwake = false;
boolean prisonerIsAwake = true;
@@ -213,7 +213,7 @@ public void can_release_prisoner_if_only_prisoner_is_awake_and_pet_dog_is_absent
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when only archer is awake and pet dog is present")
- public void cannot_release_prisoner_if_only_archer_is_awake_and_pet_dog_is_present() {
+ public void cannotReleasePrisonerIfOnlyArcherIsAwakeAndPetDogIsPresent() {
boolean knightIsAwake = false;
boolean archerIsAwake = true;
boolean prisonerIsAwake = false;
@@ -225,7 +225,7 @@ public void cannot_release_prisoner_if_only_archer_is_awake_and_pet_dog_is_prese
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when only archer is awake and pet dog is absent")
- public void cannot_release_prisoner_if_only_archer_is_awake_and_pet_dog_is_absent() {
+ public void cannotReleasePrisonerIfOnlyArcherIsAwakeAndPetDogIsAbsent() {
boolean knightIsAwake = false;
boolean archerIsAwake = true;
boolean prisonerIsAwake = false;
@@ -237,7 +237,7 @@ public void cannot_release_prisoner_if_only_archer_is_awake_and_pet_dog_is_absen
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns true when only knight is awake and pet dog is present")
- public void can_release_prisoner_if_only_knight_is_awake_and_pet_dog_is_present() {
+ public void canReleasePrisonerIfOnlyKnightIsAwakeAndPetDogIsPresent() {
boolean knightIsAwake = true;
boolean archerIsAwake = false;
boolean prisonerIsAwake = false;
@@ -249,7 +249,7 @@ public void can_release_prisoner_if_only_knight_is_awake_and_pet_dog_is_present(
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when only knight is awake and pet dog is absent")
- public void cannot_release_prisoner_if_only_knight_is_awake_and_pet_dog_is_absent() {
+ public void cannotReleasePrisonerIfOnlyKnightIsAwakeAndPetDogIsAbsent() {
boolean knightIsAwake = true;
boolean archerIsAwake = false;
boolean prisonerIsAwake = false;
@@ -261,7 +261,7 @@ public void cannot_release_prisoner_if_only_knight_is_awake_and_pet_dog_is_absen
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when only knight is sleeping and pet dog is present")
- public void cannot_release_prisoner_if_only_knight_is_asleep_and_pet_dog_is_present() {
+ public void cannotReleasePrisonerIfOnlyKnightIsAsleepAndPetDogIsPresent() {
boolean knightIsAwake = false;
boolean archerIsAwake = true;
boolean prisonerIsAwake = true;
@@ -273,7 +273,7 @@ public void cannot_release_prisoner_if_only_knight_is_asleep_and_pet_dog_is_pres
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when only knight is sleeping and pet dog is absent")
- public void cannot_release_prisoner_if_only_knight_is_asleep_and_pet_dog_is_absent() {
+ public void cannotReleasePrisonerIfOnlyKnightIsAsleepAndPetDogIsAbsent() {
boolean knightIsAwake = false;
boolean archerIsAwake = true;
boolean prisonerIsAwake = true;
@@ -285,7 +285,7 @@ public void cannot_release_prisoner_if_only_knight_is_asleep_and_pet_dog_is_abse
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns true when only archer is sleeping and pet dog is present")
- public void can_release_prisoner_if_only_archer_is_asleep_and_pet_dog_is_present() {
+ public void canReleasePrisonerIfOnlyArcherIsAsleepAndPetDogIsPresent() {
boolean knightIsAwake = true;
boolean archerIsAwake = false;
boolean prisonerIsAwake = true;
@@ -297,7 +297,7 @@ public void can_release_prisoner_if_only_archer_is_asleep_and_pet_dog_is_present
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when only archer is sleeping and pet dog is absent")
- public void cannot_release_prisoner_if_only_archer_is_asleep_and_pet_dog_is_absent() {
+ public void cannotReleasePrisonerIfOnlyArcherIsAsleepAndPetDogIsAbsent() {
boolean knightIsAwake = true;
boolean archerIsAwake = false;
boolean prisonerIsAwake = true;
@@ -309,7 +309,7 @@ public void cannot_release_prisoner_if_only_archer_is_asleep_and_pet_dog_is_abse
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when only prisoner is sleeping and pet dog is present")
- public void cannot_release_prisoner_if_only_prisoner_is_asleep_and_pet_dog_is_present() {
+ public void cannotReleasePrisonerIfOnlyPrisonerIsAsleepAndPetDogIsPresent() {
boolean knightIsAwake = true;
boolean archerIsAwake = true;
boolean prisonerIsAwake = false;
@@ -321,7 +321,7 @@ public void cannot_release_prisoner_if_only_prisoner_is_asleep_and_pet_dog_is_pr
@Test
@Tag("task:4")
@DisplayName("The canFreePrisoner method returns false when only prisoner is sleeping and pet dog is absent")
- public void cannot_release_prisoner_if_only_prisoner_is_asleep_and_pet_dog_is_absent() {
+ public void cannotReleasePrisonerIfOnlyPrisonerIsAsleepAndPetDogIsAbsent() {
boolean knightIsAwake = true;
boolean archerIsAwake = true;
boolean prisonerIsAwake = false;
diff --git a/exercises/concept/bird-watcher/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/bird-watcher/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/bird-watcher/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/bird-watcher/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/bird-watcher/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/bird-watcher/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/bird-watcher/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/bird-watcher/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/bird-watcher/gradlew b/exercises/concept/bird-watcher/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/bird-watcher/gradlew
+++ b/exercises/concept/bird-watcher/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/bird-watcher/gradlew.bat b/exercises/concept/bird-watcher/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/bird-watcher/gradlew.bat
+++ b/exercises/concept/bird-watcher/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/bird-watcher/src/test/java/BirdWatcherTest.java b/exercises/concept/bird-watcher/src/test/java/BirdWatcherTest.java
index 80ff5f8e2..5b1746082 100644
--- a/exercises/concept/bird-watcher/src/test/java/BirdWatcherTest.java
+++ b/exercises/concept/bird-watcher/src/test/java/BirdWatcherTest.java
@@ -16,7 +16,7 @@ public class BirdWatcherTest {
private static final int TODAY = 4;
private BirdWatcher birdWatcher;
- private int lastWeek[] = {DAY1, DAY2, DAY3, DAY4, DAY5, DAY6, TODAY};
+ private final int[] lastWeek = {DAY1, DAY2, DAY3, DAY4, DAY5, DAY6, TODAY};
@BeforeEach
public void setUp() {
@@ -61,6 +61,13 @@ public void itShouldNotHaveDaysWithoutBirds() {
assertThat(birdWatcher.hasDayWithoutBirds()).isFalse();
}
+ @Test
+ @Tag("task:4")
+ @DisplayName("The hasDayWithoutBirds method returns true if the last day has zero visits")
+ public void itHasLastDayWithoutBirds() {
+ birdWatcher = new BirdWatcher(new int[]{1, 2, 5, 3, 7, 8, 0});
+ assertThat(birdWatcher.hasDayWithoutBirds()).isTrue();
+ }
@Test
@Tag("task:5")
diff --git a/exercises/concept/booking-up-for-beauty/.docs/introduction.md b/exercises/concept/booking-up-for-beauty/.docs/introduction.md
index 2baa59e0f..ed132331c 100644
--- a/exercises/concept/booking-up-for-beauty/.docs/introduction.md
+++ b/exercises/concept/booking-up-for-beauty/.docs/introduction.md
@@ -43,7 +43,7 @@ These methods return a _new_ `LocalDate` instance and do not update the existing
```java
LocalDate date = LocalDate.of(2007, 12, 3);
-date.addDays(3);
+date.plusDays(3);
// => 2007-12-06
```
diff --git a/exercises/concept/booking-up-for-beauty/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/booking-up-for-beauty/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/booking-up-for-beauty/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/booking-up-for-beauty/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/booking-up-for-beauty/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/booking-up-for-beauty/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/booking-up-for-beauty/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/booking-up-for-beauty/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/booking-up-for-beauty/gradlew b/exercises/concept/booking-up-for-beauty/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/booking-up-for-beauty/gradlew
+++ b/exercises/concept/booking-up-for-beauty/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/booking-up-for-beauty/gradlew.bat b/exercises/concept/booking-up-for-beauty/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/booking-up-for-beauty/gradlew.bat
+++ b/exercises/concept/booking-up-for-beauty/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/calculator-conundrum/.docs/introduction.md b/exercises/concept/calculator-conundrum/.docs/introduction.md
index e9b19e65f..49103a297 100644
--- a/exercises/concept/calculator-conundrum/.docs/introduction.md
+++ b/exercises/concept/calculator-conundrum/.docs/introduction.md
@@ -10,11 +10,12 @@ An exception is an event that occurs during the execution of a program that disr
Exceptions are raised explicitly in Java, and the act of raising an exception is called _throwing an exception_.
The act of handling an exception is called _catching an exception_.
-Java distinguishes three types of exceptions:
+In Java, all exceptions are subclasses of the `Exception` class, which itself is a subclass of `Throwable`.
+
+Java distinguishes two types of exceptions:
1. Checked exceptions
2. Unchecked exceptions
-3. Errors
#### Checked exceptions
@@ -23,7 +24,7 @@ An example of a checked exception is the `FileNotFoundException` which occurs wh
This type of exception is checked at compile-time: methods that throw checked exceptions should specify this in their method signature, and code calling a method that might throw a checked exception is required to handle it or the code will not compile.
-All exceptions in Java that do not inherit from `RuntimeException` or `Error` are considered checked exceptions.
+All checked exceptions are subclasses of `Exception` that do not extend `RuntimeException`.
#### Unchecked exceptions
@@ -32,17 +33,7 @@ An example of an unchecked exception is the `NullPointerException` which occurs
This type of exception is not checked at compile-time: methods that throw unchecked exceptions are not required to specify this in their method signature, and code calling a method that might throw an unchecked exception is not required to handle it.
-All exceptions in Java that inherit from `RuntimeException` are considered unchecked exceptions.
-
-#### Errors
-
-_Errors_ are exceptional conditions that are external to an application.
-An example of an error is the `OutOfMemoryError` which occurs when an application is trying to use more memory than is available on the system.
-
-Like unchecked exceptions, errors are not checked at compile-time.
-They are not usually thrown from application code.
-
-All exceptions in Java that inherit from `Error` are considered errors.
+All unchecked exceptions inherit from `RuntimeException`, which itself is an extension of `Exception`.
### Throwing exceptions
@@ -136,3 +127,14 @@ Withdrawing -10.0
Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0
```
+
+### Errors
+
+Java also has a separate category called _Errors_ which are serious problems that are external to an application.
+An example of an error is the `OutOfMemoryError` which occurs when an application is trying to use more memory than is available on the system.
+
+Like unchecked exceptions, errors are not checked at compile-time.
+The difference is that they represent system level problems and are generally thrown by the Java Virtual machine or environment instead of the application.
+Applications should generally not attempt to catch or handle them.
+
+All errors in Java inherit from the `Error` class.
diff --git a/exercises/concept/calculator-conundrum/.meta/design.md b/exercises/concept/calculator-conundrum/.meta/design.md
index 5163b002c..5134eb08a 100644
--- a/exercises/concept/calculator-conundrum/.meta/design.md
+++ b/exercises/concept/calculator-conundrum/.meta/design.md
@@ -18,3 +18,15 @@
- `conditionals-if`: know how to do conditional logic.
- `switch-statement`: know how to work with a `switch` statement.
+
+## Analyzer
+
+This exercise could benefit from the following rules in the [analyzer]:
+
+- `essential`: Verify that the solution is using the try catch statement for the division.
+- `actionable`: If the solution is wrapping all the code in a try catch statement, instruct the student to only use the `try catch` for the division statement
+- `actionable`: If the solution uses only `if` statement, instruct the student that he/she can use the `switch case` statement to perform the operations.
+- `informative`: If the solution does not throw the exception for `Operation cannot be null` and `Operation cannot be empty` at the beginning, suggest the fail-fast approach to the student.
+ Inform this way of implementation can be less error-prone and more readable as suggested by Martin Fowler:
+
+[analyzer]: https://github.com/exercism/java-analyzer
diff --git a/exercises/concept/calculator-conundrum/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/calculator-conundrum/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/calculator-conundrum/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/calculator-conundrum/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/calculator-conundrum/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/calculator-conundrum/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/calculator-conundrum/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/calculator-conundrum/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/calculator-conundrum/gradlew b/exercises/concept/calculator-conundrum/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/calculator-conundrum/gradlew
+++ b/exercises/concept/calculator-conundrum/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/calculator-conundrum/gradlew.bat b/exercises/concept/calculator-conundrum/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/calculator-conundrum/gradlew.bat
+++ b/exercises/concept/calculator-conundrum/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/captains-log/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/captains-log/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/captains-log/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/captains-log/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/captains-log/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/captains-log/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/captains-log/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/captains-log/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/captains-log/gradlew b/exercises/concept/captains-log/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/captains-log/gradlew
+++ b/exercises/concept/captains-log/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/captains-log/gradlew.bat b/exercises/concept/captains-log/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/captains-log/gradlew.bat
+++ b/exercises/concept/captains-log/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/cars-assemble/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/cars-assemble/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/cars-assemble/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/cars-assemble/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/cars-assemble/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/cars-assemble/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/cars-assemble/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/cars-assemble/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/cars-assemble/gradlew b/exercises/concept/cars-assemble/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/cars-assemble/gradlew
+++ b/exercises/concept/cars-assemble/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/cars-assemble/gradlew.bat b/exercises/concept/cars-assemble/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/cars-assemble/gradlew.bat
+++ b/exercises/concept/cars-assemble/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/football-match-reports/.docs/instructions.md b/exercises/concept/football-match-reports/.docs/instructions.md
index f255c3a13..2c668b663 100644
--- a/exercises/concept/football-match-reports/.docs/instructions.md
+++ b/exercises/concept/football-match-reports/.docs/instructions.md
@@ -27,11 +27,11 @@ FootballMatchReports.onField(10);
// => "striker"
```
-## 2. Raise an alert if an unknown shirt number is encountered
+## 2. Output "invalid" if the shirt number is not part of the official list
-Modify the `FootballMatchReports.onField()` method to throw an `IllegalArgumentException` when a shirt number outside the range 1-11 is processed.
+Modify the `FootballMatchReports.onField()` method to return 'invalid' when a shirt number outside the range 1-11 is processed.
```java
FootballMatchReports.onField(13);
-// => Throw IllegalArgumentException
+// => "invalid"
```
diff --git a/exercises/concept/football-match-reports/.meta/config.json b/exercises/concept/football-match-reports/.meta/config.json
index 9b291514e..74d3894b7 100644
--- a/exercises/concept/football-match-reports/.meta/config.json
+++ b/exercises/concept/football-match-reports/.meta/config.json
@@ -2,6 +2,9 @@
"authors": [
"Azumix"
],
+ "contributors": [
+ "AlvesJorge"
+ ],
"files": {
"solution": [
"src/main/java/FootballMatchReports.java"
diff --git a/exercises/concept/football-match-reports/.meta/src/reference/java/FootballMatchReports.java b/exercises/concept/football-match-reports/.meta/src/reference/java/FootballMatchReports.java
index d18f55ac6..c99abc7b0 100644
--- a/exercises/concept/football-match-reports/.meta/src/reference/java/FootballMatchReports.java
+++ b/exercises/concept/football-match-reports/.meta/src/reference/java/FootballMatchReports.java
@@ -30,7 +30,7 @@ public static String onField(int shirtNum) {
playerDescription = "striker";
break;
default:
- throw new IllegalArgumentException();
+ playerDescription = "invalid";
}
return playerDescription;
}
diff --git a/exercises/concept/football-match-reports/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/football-match-reports/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/football-match-reports/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/football-match-reports/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/football-match-reports/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/football-match-reports/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/football-match-reports/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/football-match-reports/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/football-match-reports/gradlew b/exercises/concept/football-match-reports/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/football-match-reports/gradlew
+++ b/exercises/concept/football-match-reports/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/football-match-reports/gradlew.bat b/exercises/concept/football-match-reports/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/football-match-reports/gradlew.bat
+++ b/exercises/concept/football-match-reports/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/football-match-reports/src/test/java/FootballMatchReportsTest.java b/exercises/concept/football-match-reports/src/test/java/FootballMatchReportsTest.java
index aeaeada1d..82024e6f5 100644
--- a/exercises/concept/football-match-reports/src/test/java/FootballMatchReportsTest.java
+++ b/exercises/concept/football-match-reports/src/test/java/FootballMatchReportsTest.java
@@ -3,35 +3,34 @@
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
public class FootballMatchReportsTest {
@Test
@Tag("task:1")
@DisplayName("The onField method returns the correct description of player with shirt number 1")
- public void test_goal() {
+ public void testGoal() {
assertThat(FootballMatchReports.onField(1)).isEqualTo("goalie");
}
@Test
@Tag("task:1")
@DisplayName("The onField method returns the correct description of player with shirt number 2")
- public void test_left_back() {
+ public void testLeftBack() {
assertThat(FootballMatchReports.onField(2)).isEqualTo("left back");
}
@Test
@Tag("task:1")
@DisplayName("The onField method returns the correct description of player with shirt number 5")
- public void test_right_back() {
+ public void testRightBack() {
assertThat(FootballMatchReports.onField(5)).isEqualTo("right back");
}
@Test
@Tag("task:1")
@DisplayName("The onField method returns the correct description of players with shirt numbers 3 and 4")
- public void test_center_back() {
+ public void testCenterBack() {
assertThat(FootballMatchReports.onField(3)).isEqualTo("center back");
assertThat(FootballMatchReports.onField(4)).isEqualTo("center back");
}
@@ -39,7 +38,7 @@ public void test_center_back() {
@Test
@Tag("task:1")
@DisplayName("The onField method returns the correct description of players with shirt numbers 6, 7 and 8")
- public void test_midfielder() {
+ public void testMidfielder() {
assertThat(FootballMatchReports.onField(6)).isEqualTo("midfielder");
assertThat(FootballMatchReports.onField(7)).isEqualTo("midfielder");
assertThat(FootballMatchReports.onField(8)).isEqualTo("midfielder");
@@ -48,37 +47,35 @@ public void test_midfielder() {
@Test
@Tag("task:1")
@DisplayName("The onField method returns the correct description of player with shirt number 9")
- public void test_left_wing() {
+ public void testLeftWing() {
assertThat(FootballMatchReports.onField(9)).isEqualTo("left wing");
}
@Test
@Tag("task:1")
@DisplayName("The onField method returns the correct description of player with shirt number 10")
- public void test_striker() {
+ public void testStriker() {
assertThat(FootballMatchReports.onField(10)).isEqualTo("striker");
}
@Test
@Tag("task:1")
@DisplayName("The onField method returns the correct description of player with shirt number 11")
- public void test_right_wing() {
+ public void testRightWing() {
assertThat(FootballMatchReports.onField(11)).isEqualTo("right wing");
}
@Test
@Tag("task:2")
- @DisplayName("The onField method throws IllegalArgumentException for unknown shirt number")
- public void test_exception() {
- assertThatExceptionOfType(IllegalArgumentException.class)
- .isThrownBy(() -> FootballMatchReports.onField(13));
+ @DisplayName("The onField method returns 'invalid' for invalid shirt number")
+ public void testException() {
+ assertThat(FootballMatchReports.onField(13)).isEqualTo("invalid");
}
@Test
@Tag("task:2")
- @DisplayName("The onField method throws IllegalArgumentException for negative shirt number")
- public void test_exception_negative_number() {
- assertThatExceptionOfType(IllegalArgumentException.class)
- .isThrownBy(() -> FootballMatchReports.onField(-1));
+ @DisplayName("The onField method returns 'invalid' for negative shirt number")
+ public void testExceptionNegativeNumber() {
+ assertThat(FootballMatchReports.onField(-1)).isEqualTo("invalid");
}
}
diff --git a/exercises/concept/gotta-snatch-em-all/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/gotta-snatch-em-all/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/gotta-snatch-em-all/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/gotta-snatch-em-all/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/gotta-snatch-em-all/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/gotta-snatch-em-all/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/gotta-snatch-em-all/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/gotta-snatch-em-all/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/gotta-snatch-em-all/gradlew b/exercises/concept/gotta-snatch-em-all/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/gotta-snatch-em-all/gradlew
+++ b/exercises/concept/gotta-snatch-em-all/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/gotta-snatch-em-all/gradlew.bat b/exercises/concept/gotta-snatch-em-all/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/gotta-snatch-em-all/gradlew.bat
+++ b/exercises/concept/gotta-snatch-em-all/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/international-calling-connoisseur/.docs/hints.md b/exercises/concept/international-calling-connoisseur/.docs/hints.md
index 056edd53d..8bedc370b 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/hints.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/hints.md
@@ -22,7 +22,7 @@
## 5. Find a country's dialing code
-- There is a [way][map-values-docs] to get an iterable collection of values in a map.
+- There is a [way][map-entry-set-docs] to get an iterable collection of entries in a map, which allows you to go through the key-value pairs.
## 6. Update the country's dialing code
@@ -35,5 +35,5 @@
[map-get-docs]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html#get(java.lang.Object)
[map-contains-key-docs]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html#containsKey(java.lang.Object)
[map-contains-value-docs]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html#containsValue(java.lang.Object)
-[map-values-docs]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html#values()
+[map-entry-set-docs]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html#entrySet()
[map-remove-docs]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html#remove(java.lang.Object)
diff --git a/exercises/concept/international-calling-connoisseur/.docs/instructions.md b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
index e8f728f0f..106844176 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/instructions.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
@@ -31,7 +31,7 @@ dialingCodes.setDialingCode(679, "Fiji");
## 3. Lookup a dialing code's country
-Implement the `getCountry` method that takes a map of dialing codes and a dialing code and returns the country name with the dialing code.
+Implement the `getCountry` method that takes a dialing code and returns the country name with the dialing code.
```java
DialingCodes dialingCodes = new DialingCodes();
@@ -63,7 +63,7 @@ dialingCodes.addNewDialingCode(39, "Vatican City");
Its rare, but mistakes can be made.
To correct the mistake, we will need to know what dialing code the country is currently mapped to.
-To find which dialing code needs to be corrected, implement the `findDialingCode` method that takes in a map of dialing codes and a country and returns the country's dialing code.
+To find which dialing code needs to be corrected, implement the `findDialingCode` method that takes a country and returns the country's dialing code.
Return `null` if the country is _not_ in the map.
```java
diff --git a/exercises/concept/international-calling-connoisseur/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/international-calling-connoisseur/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/international-calling-connoisseur/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/international-calling-connoisseur/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/international-calling-connoisseur/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/international-calling-connoisseur/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/international-calling-connoisseur/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/international-calling-connoisseur/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/international-calling-connoisseur/gradlew b/exercises/concept/international-calling-connoisseur/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/international-calling-connoisseur/gradlew
+++ b/exercises/concept/international-calling-connoisseur/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/international-calling-connoisseur/gradlew.bat b/exercises/concept/international-calling-connoisseur/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/international-calling-connoisseur/gradlew.bat
+++ b/exercises/concept/international-calling-connoisseur/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/jedliks-toy-car/.meta/design.md b/exercises/concept/jedliks-toy-car/.meta/design.md
index f99cef1f7..2a1b40eb1 100644
--- a/exercises/concept/jedliks-toy-car/.meta/design.md
+++ b/exercises/concept/jedliks-toy-car/.meta/design.md
@@ -28,3 +28,15 @@
- `strings`: know how to do basic string interpolation.
- `numbers`: know how to compare numbers.
- `conditionals`: know how to do conditional logic.
+
+## Analyzer
+
+This exercise could benefit from the following rules in the [analyzer]:
+
+- `essential`: Verify that the solution keeps the void type for the drive function.
+- `essential`: Verify that the solution has fields in the class
+- `actionable`: If the solution defines the fields as `public`, instruct the student to use `private` and explain the encapsulation principle.
+- `informative`: If the solution does not use a primitive as a type for the fields, inform the student to use it.
+ Explain that the values cannot be null and it is less error-prone
+
+[analyzer]: https://github.com/exercism/java-analyzer
diff --git a/exercises/concept/jedliks-toy-car/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/jedliks-toy-car/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/jedliks-toy-car/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/jedliks-toy-car/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/jedliks-toy-car/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/jedliks-toy-car/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/jedliks-toy-car/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/jedliks-toy-car/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/jedliks-toy-car/gradlew b/exercises/concept/jedliks-toy-car/gradlew
old mode 100644
new mode 100755
index 1aa94a426..adff685a0
--- a/exercises/concept/jedliks-toy-car/gradlew
+++ b/exercises/concept/jedliks-toy-car/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/jedliks-toy-car/gradlew.bat b/exercises/concept/jedliks-toy-car/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/jedliks-toy-car/gradlew.bat
+++ b/exercises/concept/jedliks-toy-car/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/jedliks-toy-car/src/test/java/JedliksToyCarTest.java b/exercises/concept/jedliks-toy-car/src/test/java/JedliksToyCarTest.java
index 19db64391..279cf07a0 100644
--- a/exercises/concept/jedliks-toy-car/src/test/java/JedliksToyCarTest.java
+++ b/exercises/concept/jedliks-toy-car/src/test/java/JedliksToyCarTest.java
@@ -8,7 +8,7 @@ public class JedliksToyCarTest {
@Test
@Tag("task:1")
@DisplayName("The static buy method returns a new remote controlled car instance")
- public void buy_new_car_returns_instance() {
+ public void buyNewCarReturnsInstance() {
JedliksToyCar car = JedliksToyCar.buy();
assertThat(car).isNotNull();
}
@@ -16,7 +16,7 @@ public void buy_new_car_returns_instance() {
@Test
@Tag("task:1")
@DisplayName("The static buy method returns each time a new remote controlled car instance")
- public void buy_new_car_returns_new_car_each_time() {
+ public void buyNewCarReturnsNewCarEachTime() {
JedliksToyCar car1 = JedliksToyCar.buy();
JedliksToyCar car2 = JedliksToyCar.buy();
assertThat(car1).isNotEqualTo(car2);
@@ -25,7 +25,7 @@ public void buy_new_car_returns_new_car_each_time() {
@Test
@Tag("task:2")
@DisplayName("The distanceDisplay method shows 0 meters message on a new car")
- public void new_car_distance_display() {
+ public void newCarDistanceDisplay() {
JedliksToyCar car = new JedliksToyCar();
assertThat(car.distanceDisplay()).isEqualTo("Driven 0 meters");
}
@@ -33,7 +33,7 @@ public void new_car_distance_display() {
@Test
@Tag("task:3")
@DisplayName("The batteryDisplay method shows full battery message on a new car")
- public void new_car_battery_display() {
+ public void newCarBatteryDisplay() {
JedliksToyCar car = new JedliksToyCar();
assertThat(car.batteryDisplay()).isEqualTo("Battery at 100%");
}
@@ -41,7 +41,7 @@ public void new_car_battery_display() {
@Test
@Tag("task:4")
@DisplayName("The distanceDisplay method shows the correct message after driving once")
- public void distance_display_after_driving_once() {
+ public void distanceDisplayAfterDrivingOnce() {
JedliksToyCar car = new JedliksToyCar();
car.drive();
assertThat(car.distanceDisplay()).isEqualTo("Driven 20 meters");
@@ -50,7 +50,7 @@ public void distance_display_after_driving_once() {
@Test
@Tag("task:4")
@DisplayName("The distanceDisplay method shows the correct message after driving multiple times")
- public void distance_display_after_driving_multiple_times() {
+ public void distanceDisplayAfterDrivingMultipleTimes() {
JedliksToyCar car = new JedliksToyCar();
for (int i = 0; i < 17; i++) {
@@ -63,7 +63,7 @@ public void distance_display_after_driving_multiple_times() {
@Test
@Tag("task:5")
@DisplayName("The batteryDisplay method shows the correct message after driving once")
- public void battery_display_after_driving_once() {
+ public void batteryDisplayAfterDrivingOnce() {
JedliksToyCar car = new JedliksToyCar();
car.drive();
@@ -73,7 +73,7 @@ public void battery_display_after_driving_once() {
@Test
@Tag("task:5")
@DisplayName("The batteryDisplay method shows the correct battery percentage after driving multiple times")
- public void battery_display_after_driving_multiple_times() {
+ public void batteryDisplayAfterDrivingMultipleTimes() {
JedliksToyCar car = new JedliksToyCar();
for (int i = 0; i < 23; i++) {
@@ -86,7 +86,7 @@ public void battery_display_after_driving_multiple_times() {
@Test
@Tag("task:5")
@DisplayName("The batteryDisplay method shows battery empty after draining all battery")
- public void battery_display_when_battery_empty() {
+ public void batteryDisplayWhenBatteryEmpty() {
JedliksToyCar car = new JedliksToyCar();
// Drain the battery
@@ -103,7 +103,7 @@ public void battery_display_when_battery_empty() {
@Test
@Tag("task:6")
@DisplayName("The distanceDisplay method shows the correct message after driving and draining all battery")
- public void distance_display_when_battery_empty() {
+ public void distanceDisplayWhenBatteryEmpty() {
JedliksToyCar car = new JedliksToyCar();
// Drain the battery
diff --git a/exercises/concept/karls-languages/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/karls-languages/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/karls-languages/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/karls-languages/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/karls-languages/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/karls-languages/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/karls-languages/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/karls-languages/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/karls-languages/gradlew b/exercises/concept/karls-languages/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/karls-languages/gradlew
+++ b/exercises/concept/karls-languages/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/karls-languages/gradlew.bat b/exercises/concept/karls-languages/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/karls-languages/gradlew.bat
+++ b/exercises/concept/karls-languages/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/lasagna/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/lasagna/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/lasagna/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/lasagna/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/lasagna/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/lasagna/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/lasagna/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/lasagna/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/lasagna/gradlew b/exercises/concept/lasagna/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/lasagna/gradlew
+++ b/exercises/concept/lasagna/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/lasagna/gradlew.bat b/exercises/concept/lasagna/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/lasagna/gradlew.bat
+++ b/exercises/concept/lasagna/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/lasagna/src/test/java/LasagnaTest.java b/exercises/concept/lasagna/src/test/java/LasagnaTest.java
index 7b1676129..6200d47c5 100644
--- a/exercises/concept/lasagna/src/test/java/LasagnaTest.java
+++ b/exercises/concept/lasagna/src/test/java/LasagnaTest.java
@@ -11,7 +11,7 @@ public class LasagnaTest {
@Test
@Tag("task:1")
@DisplayName("Implemented the expectedMinutesInOven method")
- public void implemented_expected_minutes_in_oven() {
+ public void implementedExpectedMinutesInOven() {
assertThat(new Lasagna().hasMethod("expectedMinutesInOven"))
.withFailMessage("Method expectedMinutesInOven must be created")
.isTrue();
@@ -26,14 +26,14 @@ public void implemented_expected_minutes_in_oven() {
@Test
@Tag("task:1")
@DisplayName("The expectedMinutesInOven method returns the correct value")
- public void expected_minutes_in_oven() {
+ public void expectedMinutesInOven() {
assertThat(new Lasagna().expectedMinutesInOven()).isEqualTo(40);
}
@Test
@Tag("task:2")
@DisplayName("Implemented the remainingMinutesInOven method")
- public void implemented_remaining_minutes_in_oven() {
+ public void implementedRemainingMinutesInOven() {
assertThat(new Lasagna().hasMethod("remainingMinutesInOven", int.class))
.withFailMessage("Method remainingMinutesInOven must be created")
.isTrue();
@@ -48,14 +48,14 @@ public void implemented_remaining_minutes_in_oven() {
@Test
@Tag("task:2")
@DisplayName("The remainingMinutesInOven method calculates and returns the correct value")
- public void remaining_minutes_in_oven() {
+ public void remainingMinutesInOven() {
assertThat(new Lasagna().remainingMinutesInOven(25)).isEqualTo(15);
}
@Test
@Tag("task:3")
@DisplayName("Implemented the preparationTimeInMinutes method")
- public void implemented_preparation_time_in_minutes() {
+ public void implementedPreparationTimeInMinutes() {
assertThat(new Lasagna().hasMethod("preparationTimeInMinutes", int.class))
.withFailMessage("Method preparationTimeInMinutes must be created")
.isTrue();
@@ -70,21 +70,21 @@ public void implemented_preparation_time_in_minutes() {
@Test
@Tag("task:3")
@DisplayName("The preparationTimeInMinutes method calculates the correct value for single layer")
- public void preparation_time_in_minutes_for_one_layer() {
+ public void preparationTimeInMinutesForOneLayer() {
assertThat(new Lasagna().preparationTimeInMinutes(1)).isEqualTo(2);
}
@Test
@Tag("task:3")
@DisplayName("The preparationTimeInMinutes method calculates the correct value for multiple layers")
- public void preparation_time_in_minutes_for_multiple_layers() {
+ public void preparationTimeInMinutesForMultipleLayers() {
assertThat(new Lasagna().preparationTimeInMinutes(4)).isEqualTo(8);
}
@Test
@Tag("task:4")
@DisplayName("Implemented the totalTimeInMinutes method")
- public void implemented_total_time_in_minutes() {
+ public void implementedTotalTimeInMinutes() {
assertThat(new Lasagna().hasMethod("totalTimeInMinutes", int.class, int.class))
.withFailMessage("Method totalTimeInMinutes must be created")
.isTrue();
@@ -99,14 +99,14 @@ public void implemented_total_time_in_minutes() {
@Test
@Tag("task:4")
@DisplayName("The totalTimeInMinutes method calculates the correct value for single layer")
- public void total_time_in_minutes_for_one_layer() {
+ public void totalTimeInMinutesForOneLayer() {
assertThat(new Lasagna().totalTimeInMinutes(1, 30)).isEqualTo(32);
}
@Test
@Tag("task:4")
@DisplayName("The totalTimeInMinutes method calculates the correct value for multiple layers")
- public void total_time_in_minutes_for_multiple_layers() {
+ public void totalTimeInMinutesForMultipleLayers() {
assertThat(new Lasagna().totalTimeInMinutes(4, 8)).isEqualTo(16);
}
}
diff --git a/exercises/concept/log-levels/.docs/hints.md b/exercises/concept/log-levels/.docs/hints.md
index 8453667c5..2e5bce849 100644
--- a/exercises/concept/log-levels/.docs/hints.md
+++ b/exercises/concept/log-levels/.docs/hints.md
@@ -7,12 +7,12 @@
## 1. Get message from a log line
- Different options to search for text in a string are explored in [this tutorial][tutorial-search-text-in-string].
-- How to split strings can be seen [here][tutorial-split-strings]
+- How to split strings can be seen in [this tutorial][tutorial-split-strings]
- Removing white space is [built-in][tutorial-trim-white-space].
## 2. Get log level from a log line
-- Changing a `String`'s casing is explored [here][tutorial-changing-case-upper] and [here][tutorial-changing-case-lower].
+- Changing a `String`'s casing is explored in [this changing to upper case][tutorial-changing-case-upper] and [this changing to lower case][tutorial-changing-case-lower] tutorial.
## 3. Reformat a log line
diff --git a/exercises/concept/log-levels/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/log-levels/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/log-levels/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/log-levels/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/log-levels/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/log-levels/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/log-levels/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/log-levels/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/log-levels/gradlew b/exercises/concept/log-levels/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/log-levels/gradlew
+++ b/exercises/concept/log-levels/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/log-levels/gradlew.bat b/exercises/concept/log-levels/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/log-levels/gradlew.bat
+++ b/exercises/concept/log-levels/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/log-levels/src/test/java/LogLevelsTest.java b/exercises/concept/log-levels/src/test/java/LogLevelsTest.java
index 2fa83e375..65dd46629 100644
--- a/exercises/concept/log-levels/src/test/java/LogLevelsTest.java
+++ b/exercises/concept/log-levels/src/test/java/LogLevelsTest.java
@@ -8,56 +8,56 @@ public class LogLevelsTest {
@Test
@Tag("task:1")
@DisplayName("The message method returns the log line's message of an error log")
- public void error_message() {
+ public void errorMessage() {
assertThat(LogLevels.message("[ERROR]: Stack overflow")).isEqualTo("Stack overflow");
}
@Test
@Tag("task:1")
@DisplayName("The message method returns the log line's message of a warning log")
- public void warning_message() {
+ public void warningMessage() {
assertThat(LogLevels.message("[WARNING]: Disk almost full")).isEqualTo("Disk almost full");
}
@Test
@Tag("task:1")
@DisplayName("The message method returns the log line's message of an info log")
- public void info_message() {
+ public void infoMessage() {
assertThat(LogLevels.message("[INFO]: File moved")).isEqualTo("File moved");
}
@Test
@Tag("task:1")
@DisplayName("The message method returns the log line's message after removing leading and trailing spaces")
- public void message_with_leading_and_trailing_white_space() {
+ public void messageWithLeadingAndTrailingWhiteSpace() {
assertThat(LogLevels.message("[WARNING]: \tTimezone not set \r\n")).isEqualTo("Timezone not set");
}
@Test
@Tag("task:2")
@DisplayName("The logLevel method returns the log level of an error log line")
- public void error_log_level() {
+ public void errorLogLevel() {
assertThat(LogLevels.logLevel("[ERROR]: Disk full")).isEqualTo("error");
}
@Test
@Tag("task:2")
@DisplayName("The logLevel method returns the log level of a warning log line")
- public void warning_log_level() {
+ public void warningLogLevel() {
assertThat(LogLevels.logLevel("[WARNING]: Unsafe password")).isEqualTo("warning");
}
@Test
@Tag("task:2")
@DisplayName("The logLevel method returns the log level of an info log line")
- public void info_log_level() {
+ public void infoLogLevel() {
assertThat(LogLevels.logLevel("[INFO]: Timezone changed")).isEqualTo("info");
}
@Test
@Tag("task:3")
@DisplayName("The reformat method correctly reformats an error log line")
- public void error_reformat() {
+ public void errorReformat() {
assertThat(LogLevels.reformat("[ERROR]: Segmentation fault"))
.isEqualTo("Segmentation fault (error)");
}
@@ -65,7 +65,7 @@ public void error_reformat() {
@Test
@Tag("task:3")
@DisplayName("The reformat method correctly reformats a warning log line")
- public void warning_reformat() {
+ public void warningReformat() {
assertThat(LogLevels.reformat("[WARNING]: Decreased performance"))
.isEqualTo("Decreased performance (warning)");
}
@@ -73,7 +73,7 @@ public void warning_reformat() {
@Test
@Tag("task:3")
@DisplayName("The reformat method correctly reformats an info log line")
- public void info_reformat() {
+ public void infoReformat() {
assertThat(LogLevels.reformat("[INFO]: Disk defragmented"))
.isEqualTo("Disk defragmented (info)");
}
@@ -81,7 +81,7 @@ public void info_reformat() {
@Test
@Tag("task:3")
@DisplayName("The reformat method correctly reformats an error log line removing spaces")
- public void reformat_with_leading_and_trailing_white_space() {
+ public void reformatWithLeadingAndTrailingWhiteSpace() {
assertThat(LogLevels.reformat("[ERROR]: \t Corrupt disk\t \t \r\n"))
.isEqualTo("Corrupt disk (error)");
}
diff --git a/exercises/concept/logs-logs-logs/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/logs-logs-logs/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/logs-logs-logs/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/logs-logs-logs/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/logs-logs-logs/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/logs-logs-logs/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/logs-logs-logs/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/logs-logs-logs/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/logs-logs-logs/gradlew b/exercises/concept/logs-logs-logs/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/logs-logs-logs/gradlew
+++ b/exercises/concept/logs-logs-logs/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/logs-logs-logs/gradlew.bat b/exercises/concept/logs-logs-logs/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/logs-logs-logs/gradlew.bat
+++ b/exercises/concept/logs-logs-logs/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/need-for-speed/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/need-for-speed/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/need-for-speed/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/need-for-speed/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/need-for-speed/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/need-for-speed/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/need-for-speed/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/need-for-speed/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/need-for-speed/gradlew b/exercises/concept/need-for-speed/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/need-for-speed/gradlew
+++ b/exercises/concept/need-for-speed/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/need-for-speed/gradlew.bat b/exercises/concept/need-for-speed/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/need-for-speed/gradlew.bat
+++ b/exercises/concept/need-for-speed/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/need-for-speed/src/test/java/NeedForSpeedTest.java b/exercises/concept/need-for-speed/src/test/java/NeedForSpeedTest.java
index a5f130e3f..2848f34fb 100644
--- a/exercises/concept/need-for-speed/src/test/java/NeedForSpeedTest.java
+++ b/exercises/concept/need-for-speed/src/test/java/NeedForSpeedTest.java
@@ -10,7 +10,7 @@ public class NeedForSpeedTest {
@Test
@Tag("task:3")
@DisplayName("The distanceDriven method returns 0 on a new car")
- public void new_remote_control_car_has_not_driven_any_distance() {
+ public void newRemoteControlCarHasNotDrivenAnyDistance() {
int speed = 10;
int batteryDrain = 2;
var car = new NeedForSpeed(speed, batteryDrain);
@@ -21,7 +21,7 @@ public void new_remote_control_car_has_not_driven_any_distance() {
@Test
@Tag("task:3")
@DisplayName("The distanceDriven method returns 5 after driving once")
- public void drive_increases_distance_driven_with_speed() {
+ public void driveIncreasesDistanceDrivenWithSpeed() {
int speed = 5;
int batteryDrain = 1;
var car = new NeedForSpeed(speed, batteryDrain);
@@ -34,7 +34,7 @@ public void drive_increases_distance_driven_with_speed() {
@Test
@Tag("task:3")
@DisplayName("The distanceDriven method returns the correct distance after driving multiple times")
- public void drive_does_not_increase_distance_driven_when_battery_drained() {
+ public void driveDoesNotIncreaseDistanceDrivenWhenBatteryDrained() {
int speed = 9;
int batteryDrain = 50;
var car = new NeedForSpeed(speed, batteryDrain);
@@ -52,7 +52,7 @@ public void drive_does_not_increase_distance_driven_when_battery_drained() {
@Test
@Tag("task:4")
@DisplayName("The batteryDrained method returns false when car never drove")
- public void new_remote_control_car_battery_is_not_drained() {
+ public void newRemoteControlCarBatteryIsNotDrained() {
int speed = 15;
int batteryDrain = 3;
var car = new NeedForSpeed(speed, batteryDrain);
@@ -63,7 +63,7 @@ public void new_remote_control_car_battery_is_not_drained() {
@Test
@Tag("task:4")
@DisplayName("The batteryDrained method returns false when there's not enough battery")
- public void new_remote_control_car_that_can_only_drive_once() {
+ public void newRemoteControlCarThatCanOnlyDriveOnce() {
var car = new NeedForSpeed(1, 99);
car.drive();
assertThat(car.batteryDrained()).isTrue();
@@ -74,7 +74,7 @@ public void new_remote_control_car_that_can_only_drive_once() {
@Test
@Tag("task:4")
@DisplayName("The batteryDrained method returns false when car battery did not completely drain after driving")
- public void drive_to_almost_drain_battery() {
+ public void driveToAlmostDrainBattery() {
int speed = 2;
int batteryDrain = 1;
var car = new NeedForSpeed(speed, batteryDrain);
@@ -90,7 +90,7 @@ public void drive_to_almost_drain_battery() {
@Test
@Tag("task:4")
@DisplayName("The batteryDrained method returns true when battery completely drained after driving")
- public void drive_until_battery_is_drained() {
+ public void driveUntilBatteryIsDrained() {
int speed = 2;
int batteryDrain = 1;
var car = new NeedForSpeed(speed, batteryDrain);
@@ -106,7 +106,7 @@ public void drive_until_battery_is_drained() {
@Test
@Tag("task:5")
@DisplayName("The distanceDriven method returns 0 on a new nitro car")
- public void nitro_car_has_not_driven_any_distance() {
+ public void nitroCarHasNotDrivenAnyDistance() {
var car = NeedForSpeed.nitro();
assertThat(car.distanceDriven()).isEqualTo(0);
}
@@ -114,7 +114,7 @@ public void nitro_car_has_not_driven_any_distance() {
@Test
@Tag("task:5")
@DisplayName("The batteryDrained method returns false when nitro car never drove")
- public void nitro_car_has_battery_not_drained() {
+ public void nitroCarHasBatteryNotDrained() {
var car = NeedForSpeed.nitro();
assertThat(car.batteryDrained()).isFalse();
}
@@ -122,7 +122,7 @@ public void nitro_car_has_battery_not_drained() {
@Test
@Tag("task:5")
@DisplayName("The distanceDriven method returns the correct distance after driving a nitro car")
- public void nitro_car_has_correct_speed() {
+ public void nitroCarHasCorrectSpeed() {
var car = NeedForSpeed.nitro();
car.drive();
assertThat(car.distanceDriven()).isEqualTo(50);
@@ -131,7 +131,7 @@ public void nitro_car_has_correct_speed() {
@Test
@Tag("task:5")
@DisplayName("The batteryDrained method returns false when nitro battery did not completely drain after driving")
- public void nitro_has_correct_battery_drain() {
+ public void nitroHasCorrectBatteryDrain() {
var car = NeedForSpeed.nitro();
// The battery is almost drained
@@ -145,7 +145,7 @@ public void nitro_has_correct_battery_drain() {
@Test
@Tag("task:5")
@DisplayName("The batteryDrained method returns true when nitro battery completely drained after driving")
- public void nitro_battery_completely_drains() {
+ public void nitroBatteryCompletelyDrains() {
var car = NeedForSpeed.nitro();
// The battery is drained
@@ -159,7 +159,7 @@ public void nitro_battery_completely_drains() {
@Test
@Tag("task:6")
@DisplayName("The canFinishRace method returns true when car can finish a race")
- public void car_can_finish_with_car_that_can_easily_finish() {
+ public void carCanFinishWithCarThatCanEasilyFinish() {
int speed = 10;
int batteryDrain = 2;
var car = new NeedForSpeed(speed, batteryDrain);
@@ -173,7 +173,7 @@ public void car_can_finish_with_car_that_can_easily_finish() {
@Test
@Tag("task:6")
@DisplayName("The canFinishRace method returns true when car can just finish a race")
- public void car_can_finish_with_car_that_can_just_finish() {
+ public void carCanFinishWithCarThatCanJustFinish() {
int speed = 2;
int batteryDrain = 10;
var car = new NeedForSpeed(speed, batteryDrain);
@@ -187,7 +187,7 @@ public void car_can_finish_with_car_that_can_just_finish() {
@Test
@Tag("task:6")
@DisplayName("The canFinishRace method returns false when car just cannot finish a race")
- public void car_can_finish_with_car_that_just_cannot_finish() {
+ public void carCanFinishWithCarThatJustCannotFinish() {
int speed = 3;
int batteryDrain = 20;
var car = new NeedForSpeed(speed, batteryDrain);
@@ -201,7 +201,7 @@ public void car_can_finish_with_car_that_just_cannot_finish() {
@Test
@Tag("task:6")
@DisplayName("The canFinishRace method returns false when car cannot finish a race")
- public void car_can_finish_with_car_that_cannot_finish() {
+ public void carCanFinishWithCarThatCannotFinish() {
int speed = 1;
int batteryDrain = 20;
var car = new NeedForSpeed(speed, batteryDrain);
diff --git a/exercises/concept/remote-control-competition/.docs/hints.md b/exercises/concept/remote-control-competition/.docs/hints.md
index 1b48b5515..fbd4ebfa7 100644
--- a/exercises/concept/remote-control-competition/.docs/hints.md
+++ b/exercises/concept/remote-control-competition/.docs/hints.md
@@ -15,7 +15,7 @@
## 3. Allow the production cars to be ranked
- See [this discussion][sort] of sorting.
-- See [here][comparable] for default comparison of objects.
+- See [Comparable's Javadocs][comparable] for default comparison of objects.
[interfaces]: https://docs.oracle.com/javase/tutorial/java/concepts/interface.html
[sort]: https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html
diff --git a/exercises/concept/remote-control-competition/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/remote-control-competition/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/remote-control-competition/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/remote-control-competition/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/remote-control-competition/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/remote-control-competition/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/remote-control-competition/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/remote-control-competition/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/remote-control-competition/gradlew b/exercises/concept/remote-control-competition/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/remote-control-competition/gradlew
+++ b/exercises/concept/remote-control-competition/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/remote-control-competition/gradlew.bat b/exercises/concept/remote-control-competition/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/remote-control-competition/gradlew.bat
+++ b/exercises/concept/remote-control-competition/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/salary-calculator/.docs/hints.md b/exercises/concept/salary-calculator/.docs/hints.md
index 1c74c7964..68df6d809 100644
--- a/exercises/concept/salary-calculator/.docs/hints.md
+++ b/exercises/concept/salary-calculator/.docs/hints.md
@@ -2,7 +2,7 @@
## General
-- Refer to examples [here][ternary-operator-first] and [here][ternary-operator-second] for guidance on using _ternary operators_.
+- Refer to examples in [this article][ternary-operator-first] and [this one][ternary-operator-second] for guidance on using _ternary operators_.
## 1. Determine the salary multiplier
diff --git a/exercises/concept/salary-calculator/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/salary-calculator/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/salary-calculator/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/salary-calculator/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/salary-calculator/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/salary-calculator/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/salary-calculator/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/salary-calculator/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/salary-calculator/gradlew b/exercises/concept/salary-calculator/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/salary-calculator/gradlew
+++ b/exercises/concept/salary-calculator/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/salary-calculator/gradlew.bat b/exercises/concept/salary-calculator/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/salary-calculator/gradlew.bat
+++ b/exercises/concept/salary-calculator/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/secrets/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/secrets/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/secrets/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/secrets/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/secrets/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/secrets/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/secrets/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/secrets/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/secrets/gradlew b/exercises/concept/secrets/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/secrets/gradlew
+++ b/exercises/concept/secrets/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/secrets/gradlew.bat b/exercises/concept/secrets/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/secrets/gradlew.bat
+++ b/exercises/concept/secrets/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/squeaky-clean/.docs/introduction.md b/exercises/concept/squeaky-clean/.docs/introduction.md
index 15e81f074..016475918 100644
--- a/exercises/concept/squeaky-clean/.docs/introduction.md
+++ b/exercises/concept/squeaky-clean/.docs/introduction.md
@@ -2,13 +2,88 @@
## Chars
-The Java `char` type represents the smallest addressable components of text.
-Multiple `char`s can comprise a string such as `"word"` or `char`s can be processed independently.
-Their literals have single quotes e.g. `'A'`.
+### chars
+
+The Java `char` primitive type is a 16 bit representation of a single character.
+Multiple `char`s can comprise a string, such as `"word"`, or `char`s can be processed independently.
+A `char` literal is surrounded by single quotes (e.g. `'A'`).
+
+```java
+char lowerA = 'a';
+char upperB = 'B';
+```
+
+### Getting the `char`s of a `String`
+
+The `String.toCharArray` method returns a String's chars as an array.
+As mentioned in arrays, you can use a `for` loop to iterate over the array.
+
+```java
+String text = "Hello";
+char[] asArray = text.toCharArray();
+
+for (char ch: asArray) {
+ System.out.println(ch);
+}
+
+// Outputs:
+// H
+// e
+// l
+// l
+// o
+```
+
+### The Character class
There are many builtin library methods to inspect and manipulate `char`s.
These can be found as static methods of the `java.lang.Character` class.
+Here are some examples:
+
+```java
+Character.isWhitespace(' '); // true
+Character.isWhitespace('#'); // false
+
+Character.isLetter('a'); // true
+Character.isLetter('3'); // false
+
+Character.isDigit('6'); // true
+Character.isDigit('?'); // false
+```
+
+### Adding a `char` to a `String`
+
+The `+` operator can be used to add a `char` to a `String`.
+
+```java
+'a' + " banana" // => "a banana"
+"banana " + 'a' // => "banana a"
+```
+
+~~~~exercism/caution
+Becareful _not_ to use `+` to join two `char`s together to form a `String`!
+Adding two `char`s this way gives an `int`, _not_ a `String`!
+For example:
+
+```java
+'b' + 'c';
+// => 197 (not the String "bc")
+```
+
+This is because Java promotes the `char` to an `int` (see [4.2 Primitive Types and Values ][jls-primitives] of the [Java Language Specification][jls-main]).
+
+[jls-main]: https://docs.oracle.com/javase/specs/jls/se21/html/
+[jls-primitives]: https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html#jls-4.2
+~~~~
+
+However, when there are many characters to be added, it can be more efficient to use a `StringBuilder` instead:
+
+```java
+StringBuilder builder = new StringBuilder();
+builder.append('a');
+builder.append('b');
+builder.append('c');
-`char`s are sometimes used in conjunction with a `StringBuilder` object.
-This object has methods that allow a string to be constructed character by character and manipulated.
-At the end of the process `toString` can be called on it to output a complete string.
+String builtString = builder.toString();
+// => abc
+```
diff --git a/exercises/concept/squeaky-clean/.meta/config.json b/exercises/concept/squeaky-clean/.meta/config.json
index b8380b192..70df5ac7d 100644
--- a/exercises/concept/squeaky-clean/.meta/config.json
+++ b/exercises/concept/squeaky-clean/.meta/config.json
@@ -4,6 +4,7 @@
],
"contributors": [
"jagdish-15",
+ "kahgoh",
"manumafe98",
"mrDonoghue",
"sanderploegsma"
diff --git a/exercises/concept/squeaky-clean/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/squeaky-clean/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/squeaky-clean/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/squeaky-clean/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/squeaky-clean/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/squeaky-clean/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/squeaky-clean/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/squeaky-clean/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/squeaky-clean/gradlew b/exercises/concept/squeaky-clean/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/squeaky-clean/gradlew
+++ b/exercises/concept/squeaky-clean/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/squeaky-clean/gradlew.bat b/exercises/concept/squeaky-clean/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/squeaky-clean/gradlew.bat
+++ b/exercises/concept/squeaky-clean/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/squeaky-clean/src/test/java/SqueakyCleanTest.java b/exercises/concept/squeaky-clean/src/test/java/SqueakyCleanTest.java
index 19688de55..e85a60495 100644
--- a/exercises/concept/squeaky-clean/src/test/java/SqueakyCleanTest.java
+++ b/exercises/concept/squeaky-clean/src/test/java/SqueakyCleanTest.java
@@ -16,7 +16,7 @@ public void empty() {
@Test
@Tag("task:1")
@DisplayName("The clean method returns the same string when invoked on a single letter string")
- public void single_letter() {
+ public void singleLetter() {
assertThat(SqueakyClean.clean("A")).isEqualTo("A");
}
@@ -37,56 +37,56 @@ public void spaces() {
@Test
@Tag("task:1")
@DisplayName("The clean method replaces leading and trailing whitespaces with underscores")
- public void leading_and_trailing_spaces() {
+ public void leadingAndTrailingSpaces() {
assertThat(SqueakyClean.clean(" myId ")).isEqualTo("_myId_");
}
@Test
@Tag("task:2")
@DisplayName("The clean method converts kebab to camel case after removing a dash")
- public void kebab_to_camel_case() {
+ public void kebabToCamelCase() {
assertThat(SqueakyClean.clean("a-bc")).isEqualTo("aBc");
}
@Test
@Tag("task:2")
@DisplayName("The clean method returns a string in camel case after removing a dash and replaces a whitespace")
- public void kebab_to_camel_case_and_number() {
+ public void kebabToCamelCaseAndNumber() {
assertThat(SqueakyClean.clean("a-C ")).isEqualTo("aC_");
}
@Test
@Tag("task:2")
@DisplayName("The clean method returns a string in camel case and replaces leading and trailing whitespaces")
- public void kebab_to_camel_case_and_spaces() {
+ public void kebabToCamelCaseAndSpaces() {
assertThat(SqueakyClean.clean(" hello-world ")).isEqualTo("_helloWorld_");
}
@Test
@Tag("task:3")
@DisplayName("The clean method converts leetspeak to normal text after replacing numbers with chars")
- public void leetspeak_to_normal_text() {
+ public void leetspeakToNormalText() {
assertThat(SqueakyClean.clean("H3ll0 W0rld")).isEqualTo("Hello_World");
}
@Test
@Tag("task:3")
@DisplayName("The clean method converts leetspeak to normal text with spaces and special characters")
- public void leetspeak_to_normal_text_with_spaces_and_special_characters() {
+ public void leetspeakToNormalTextWithSpacesAndSpecialCharacters() {
assertThat(SqueakyClean.clean("¡1337sp34k is fun!")).isEqualTo("leetspeak_is_fun");
}
@Test
@Tag("task:4")
@DisplayName("The clean method removes all characters that are not letters")
- public void special_characters() {
+ public void specialCharacters() {
assertThat(SqueakyClean.clean("a$#.b")).isEqualTo("ab");
}
@Test
@Tag("task:4")
@DisplayName("The clean method removes all characters that are not letters and replaces spaces")
- public void special_characters_and_spaces() {
+ public void specialCharactersAndSpaces() {
assertThat(SqueakyClean.clean("¡hello world!. ")).isEqualTo("hello_world_");
}
}
diff --git a/exercises/concept/tim-from-marketing/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/tim-from-marketing/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/tim-from-marketing/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/tim-from-marketing/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/tim-from-marketing/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/tim-from-marketing/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/tim-from-marketing/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/tim-from-marketing/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/tim-from-marketing/gradlew b/exercises/concept/tim-from-marketing/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/tim-from-marketing/gradlew
+++ b/exercises/concept/tim-from-marketing/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/tim-from-marketing/gradlew.bat b/exercises/concept/tim-from-marketing/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/tim-from-marketing/gradlew.bat
+++ b/exercises/concept/tim-from-marketing/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/wizards-and-warriors-2/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/wizards-and-warriors-2/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/wizards-and-warriors-2/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/wizards-and-warriors-2/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/wizards-and-warriors-2/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/wizards-and-warriors-2/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/wizards-and-warriors-2/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/wizards-and-warriors-2/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/wizards-and-warriors-2/gradlew b/exercises/concept/wizards-and-warriors-2/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/wizards-and-warriors-2/gradlew
+++ b/exercises/concept/wizards-and-warriors-2/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/wizards-and-warriors-2/gradlew.bat b/exercises/concept/wizards-and-warriors-2/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/wizards-and-warriors-2/gradlew.bat
+++ b/exercises/concept/wizards-and-warriors-2/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/concept/wizards-and-warriors/.docs/hints.md b/exercises/concept/wizards-and-warriors/.docs/hints.md
index ab6871b2f..d9d52fc58 100644
--- a/exercises/concept/wizards-and-warriors/.docs/hints.md
+++ b/exercises/concept/wizards-and-warriors/.docs/hints.md
@@ -13,7 +13,7 @@ The whole inheritance concept has a lot to do with the concepts around [overridi
## 2. Describe a Warrior
- In Java, the `toString()` method is actually present inside the `Object` class (which is a superclass to all the classes in Java).
- You can read more about it [here][object-class-java].
+ You can read more about it at the official [Oracle documentation][object-class-java].
- To override this method inside your implementation class, you should have a method with same name i.e. `toString()` and same return type i.e. `String`.
- The `toString()` method must be `public`.
@@ -34,7 +34,7 @@ The whole inheritance concept has a lot to do with the concepts around [overridi
## 6. Describe a Wizard
- In Java, the `toString()` method is actually present inside the `Object` class (which is a superclass to all the classes in Java).
- You can read more about it [here][object-class-java].
+ You can read more about it at the official [Oracle documentation][object-class-java].
- To override this method inside your implementation class, you should have a method with same name i.e. `toString()` and same return type i.e. `String`.
- The `toString()` method must be `public`.
diff --git a/exercises/concept/wizards-and-warriors/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/wizards-and-warriors/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/concept/wizards-and-warriors/gradle/wrapper/gradle-wrapper.jar and b/exercises/concept/wizards-and-warriors/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/concept/wizards-and-warriors/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/wizards-and-warriors/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/concept/wizards-and-warriors/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/concept/wizards-and-warriors/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/concept/wizards-and-warriors/gradlew b/exercises/concept/wizards-and-warriors/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/concept/wizards-and-warriors/gradlew
+++ b/exercises/concept/wizards-and-warriors/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/concept/wizards-and-warriors/gradlew.bat b/exercises/concept/wizards-and-warriors/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/concept/wizards-and-warriors/gradlew.bat
+++ b/exercises/concept/wizards-and-warriors/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/gradle/wrapper/gradle-wrapper.jar b/exercises/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/gradle/wrapper/gradle-wrapper.jar and b/exercises/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/gradle/wrapper/gradle-wrapper.properties b/exercises/gradle/wrapper/gradle-wrapper.properties
index b82aa23a4..23449a2b5 100644
--- a/exercises/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/exercises/gradlew b/exercises/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/gradlew
+++ b/exercises/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/gradlew.bat b/exercises/gradlew.bat
index 93e3f59f1..c4bdd3ab8 100644
--- a/exercises/gradlew.bat
+++ b/exercises/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/acronym/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/acronym/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/acronym/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/acronym/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/acronym/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/acronym/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/acronym/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/acronym/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/acronym/gradlew b/exercises/practice/acronym/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/acronym/gradlew
+++ b/exercises/practice/acronym/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/acronym/gradlew.bat b/exercises/practice/acronym/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/acronym/gradlew.bat
+++ b/exercises/practice/acronym/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/acronym/src/test/java/AcronymTest.java b/exercises/practice/acronym/src/test/java/AcronymTest.java
index 4cc09f4cf..09b419c4a 100644
--- a/exercises/practice/acronym/src/test/java/AcronymTest.java
+++ b/exercises/practice/acronym/src/test/java/AcronymTest.java
@@ -1,11 +1,13 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class AcronymTest {
-
+
@Test
+ @DisplayName("basic")
public void basic() {
assertThat(new Acronym("Portable Network Graphics").get())
.isEqualTo("PNG");
@@ -13,6 +15,7 @@ public void basic() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("lowercase words")
public void lowercaseWords() {
assertThat(new Acronym("Ruby on Rails").get())
.isEqualTo("ROR");
@@ -20,6 +23,7 @@ public void lowercaseWords() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("punctuation")
public void punctuation() {
assertThat(new Acronym("First In, First Out").get())
.isEqualTo("FIFO");
@@ -27,6 +31,7 @@ public void punctuation() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("all caps word")
public void nonAcronymAllCapsWord() {
assertThat(new Acronym("GNU Image Manipulation Program").get())
.isEqualTo("GIMP");
@@ -34,6 +39,7 @@ public void nonAcronymAllCapsWord() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("punctuation without whitespace")
public void punctuationWithoutWhitespace() {
assertThat(new Acronym("Complementary metal-oxide semiconductor").get())
.isEqualTo("CMOS");
@@ -41,6 +47,7 @@ public void punctuationWithoutWhitespace() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("very long abbreviation")
public void veryLongAbbreviation() {
assertThat(new Acronym("Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me").get())
.isEqualTo("ROTFLSHTMDCOALM");
@@ -48,6 +55,7 @@ public void veryLongAbbreviation() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("consecutive delimiters")
public void consecutiveDelimiters() {
assertThat(new Acronym("Something - I made up from thin air").get())
.isEqualTo("SIMUFTA");
@@ -55,6 +63,7 @@ public void consecutiveDelimiters() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("apostrophes")
public void apostrophes() {
assertThat(new Acronym("Halley's Comet").get())
.isEqualTo("HC");
@@ -62,6 +71,7 @@ public void apostrophes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("underscore emphasis")
public void underscoreEmphasis() {
assertThat(new Acronym("The Road _Not_ Taken").get())
.isEqualTo("TRNT");
diff --git a/exercises/practice/affine-cipher/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/affine-cipher/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/affine-cipher/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/affine-cipher/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/affine-cipher/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/affine-cipher/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/affine-cipher/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/affine-cipher/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/affine-cipher/gradlew b/exercises/practice/affine-cipher/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/affine-cipher/gradlew
+++ b/exercises/practice/affine-cipher/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/affine-cipher/gradlew.bat b/exercises/practice/affine-cipher/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/affine-cipher/gradlew.bat
+++ b/exercises/practice/affine-cipher/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/affine-cipher/src/test/java/AffineCipherTest.java b/exercises/practice/affine-cipher/src/test/java/AffineCipherTest.java
index d37c96ade..25bad1a0b 100644
--- a/exercises/practice/affine-cipher/src/test/java/AffineCipherTest.java
+++ b/exercises/practice/affine-cipher/src/test/java/AffineCipherTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -9,18 +10,20 @@ public class AffineCipherTest {
private AffineCipher affineCipher = new AffineCipher();
@Test
+ @DisplayName("encode yes")
public void testEncodeYes() {
assertThat(affineCipher.encode("yes", 5, 7)).isEqualTo("xbt");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode no")
public void testEncodeNo() {
assertThat(affineCipher.encode("no", 15, 18)).isEqualTo("fu");
}
-
@Disabled("Remove to run test")
+ @DisplayName("encode OMG")
@Test
public void testEncodeOMG() {
assertThat(affineCipher.encode("OMG", 21, 3)).isEqualTo("lvz");
@@ -28,18 +31,21 @@ public void testEncodeOMG() {
@Disabled("Remove to run test")
@Test
- public void testEncodeO_M_G() {
+ @DisplayName("encode O M G")
+ public void testEncodeOMGWithSpaces() {
assertThat(affineCipher.encode("O M G", 25, 47)).isEqualTo("hjp");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode mindblowingly")
public void testEncodeMindBlowingly() {
assertThat(affineCipher.encode("mindblowingly", 11, 15)).isEqualTo("rzcwa gnxzc dgt");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode numbers")
public void testEncodeNumbers() {
assertThat(affineCipher.encode("Testing,1 2 3, testing.", 3, 4))
.isEqualTo("jqgjc rw123 jqgjc rw");
@@ -47,6 +53,7 @@ public void testEncodeNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode deep thought")
public void testEncodeDeepThought() {
assertThat(affineCipher.encode("Truth is fiction.", 5, 17))
.isEqualTo("iynia fdqfb ifje");
@@ -54,6 +61,7 @@ public void testEncodeDeepThought() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode all the letters")
public void testEncodeAllTheLetters() {
assertThat(affineCipher.encode("The quick brown fox jumps over the lazy dog.", 17, 33))
.isEqualTo("swxtj npvyk lruol iejdc blaxk swxmh qzglf");
@@ -61,6 +69,7 @@ public void testEncodeAllTheLetters() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode with a not coprime to m")
public void testEncodeThrowsMeaningfulException() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> affineCipher.encode("This is a test", 6, 17))
@@ -69,6 +78,7 @@ public void testEncodeThrowsMeaningfulException() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode exercism")
public void testDecodeExercism() {
assertThat(affineCipher.decode("tytgn fjr", 3, 7))
.isEqualTo("exercism");
@@ -76,6 +86,7 @@ public void testDecodeExercism() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode a sentence")
public void testDecodeSentence() {
assertThat(affineCipher.decode("qdwju nqcro muwhn odqun oppmd aunwd o", 19, 16))
.isEqualTo("anobstacleisoftenasteppingstone");
@@ -83,6 +94,7 @@ public void testDecodeSentence() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode numbers")
public void testDecodeNumbers() {
assertThat(affineCipher.decode("odpoz ub123 odpoz ub", 25, 7))
.isEqualTo("testing123testing");
@@ -90,6 +102,7 @@ public void testDecodeNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode all the letters")
public void testDecodeAllTheLetters() {
assertThat(affineCipher.decode("swxtj npvyk lruol iejdc blaxk swxmh qzglf", 17, 33))
.isEqualTo("thequickbrownfoxjumpsoverthelazydog");
@@ -97,6 +110,7 @@ public void testDecodeAllTheLetters() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode with no spaces in input")
public void testDecodeWithNoSpaces() {
assertThat(affineCipher.decode("swxtjnpvyklruoliejdcblaxkswxmhqzglf", 17, 33))
.isEqualTo("thequickbrownfoxjumpsoverthelazydog");
@@ -104,6 +118,7 @@ public void testDecodeWithNoSpaces() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode with too many spaces")
public void testDecodeWithTooManySpaces() {
assertThat(affineCipher.decode("vszzm cly yd cg qdp", 15, 16))
.isEqualTo("jollygreengiant");
@@ -111,6 +126,7 @@ public void testDecodeWithTooManySpaces() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode with a not coprime to m")
public void testDecodeThrowsMeaningfulException() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> affineCipher.decode("Test", 13, 5))
diff --git a/exercises/practice/all-your-base/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/all-your-base/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/all-your-base/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/all-your-base/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/all-your-base/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/all-your-base/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/all-your-base/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/all-your-base/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/all-your-base/gradlew b/exercises/practice/all-your-base/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/all-your-base/gradlew
+++ b/exercises/practice/all-your-base/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/all-your-base/gradlew.bat b/exercises/practice/all-your-base/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/all-your-base/gradlew.bat
+++ b/exercises/practice/all-your-base/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/all-your-base/src/test/java/BaseConverterTest.java b/exercises/practice/all-your-base/src/test/java/BaseConverterTest.java
index c84e97af0..c2ca95a70 100644
--- a/exercises/practice/all-your-base/src/test/java/BaseConverterTest.java
+++ b/exercises/practice/all-your-base/src/test/java/BaseConverterTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -7,6 +8,7 @@
public class BaseConverterTest {
@Test
+ @DisplayName("single bit one to decimal")
public void testSingleBitOneToDecimal() {
BaseConverter baseConverter = new BaseConverter(2, new int[]{1});
@@ -16,6 +18,7 @@ public void testSingleBitOneToDecimal() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("binary to single decimal")
public void testBinaryToSingleDecimal() {
BaseConverter baseConverter = new BaseConverter(2, new int[]{1, 0, 1});
@@ -25,6 +28,7 @@ public void testBinaryToSingleDecimal() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("single decimal to binary")
public void testSingleDecimalToBinary() {
BaseConverter baseConverter = new BaseConverter(10, new int[]{5});
@@ -34,6 +38,7 @@ public void testSingleDecimalToBinary() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("binary to multiple decimal")
public void testBinaryToMultipleDecimal() {
BaseConverter baseConverter = new BaseConverter(2, new int[]{1, 0, 1, 0, 1, 0});
@@ -43,6 +48,7 @@ public void testBinaryToMultipleDecimal() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decimal to binary")
public void testDecimalToBinary() {
BaseConverter baseConverter = new BaseConverter(10, new int[]{4, 2});
@@ -52,6 +58,7 @@ public void testDecimalToBinary() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("trinary to hexadecimal")
public void testTrinaryToHexadecimal() {
BaseConverter baseConverter = new BaseConverter(3, new int[]{1, 1, 2, 0});
@@ -61,6 +68,7 @@ public void testTrinaryToHexadecimal() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("hexadecimal to trinary")
public void testHexadecimalToTrinary() {
BaseConverter baseConverter = new BaseConverter(16, new int[]{2, 10});
@@ -70,6 +78,7 @@ public void testHexadecimalToTrinary() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("15-bit integer")
public void test15BitInteger() {
BaseConverter baseConverter = new BaseConverter(97, new int[]{3, 46, 60});
@@ -79,6 +88,7 @@ public void test15BitInteger() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("empty list")
public void testEmptyDigits() {
BaseConverter baseConverter = new BaseConverter(2, new int[]{});
@@ -88,6 +98,7 @@ public void testEmptyDigits() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("single zero")
public void testSingleZero() {
BaseConverter baseConverter = new BaseConverter(10, new int[]{0});
@@ -97,6 +108,7 @@ public void testSingleZero() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("multiple zeros")
public void testMultipleZeros() {
BaseConverter baseConverter = new BaseConverter(10, new int[]{0, 0, 0});
@@ -106,6 +118,7 @@ public void testMultipleZeros() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("leading zeros")
public void testLeadingZeros() {
BaseConverter baseConverter = new BaseConverter(7, new int[]{0, 6, 0});
@@ -115,22 +128,25 @@ public void testLeadingZeros() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("input base is one")
public void testFirstBaseIsOne() {
assertThatExceptionOfType(IllegalArgumentException.class)
- .isThrownBy(() -> new BaseConverter(1, new int[]{1}))
+ .isThrownBy(() -> new BaseConverter(1, new int[]{0}))
.withMessage("Bases must be at least 2.");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("input base is zero")
public void testFirstBaseIsZero() {
assertThatExceptionOfType(IllegalArgumentException.class)
- .isThrownBy(() -> new BaseConverter(0, new int[]{1}))
+ .isThrownBy(() -> new BaseConverter(0, new int[]{}))
.withMessage("Bases must be at least 2.");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("input base is negative")
public void testFirstBaseIsNegative() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> new BaseConverter(-2, new int[]{1}))
@@ -139,6 +155,7 @@ public void testFirstBaseIsNegative() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative digit")
public void testNegativeDigit() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> new BaseConverter(2, new int[]{1, -1, 1, 0, 1, 0}))
@@ -147,6 +164,7 @@ public void testNegativeDigit() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("invalid positive digit")
public void testInvalidPositiveDigit() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> new BaseConverter(2, new int[]{1, 2, 1, 0, 1, 0}))
@@ -155,6 +173,7 @@ public void testInvalidPositiveDigit() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("output base is one")
public void testSecondBaseIsOne() {
BaseConverter baseConverter =
new BaseConverter(2, new int[]{1, 0, 1, 0, 1, 0});
@@ -166,6 +185,7 @@ public void testSecondBaseIsOne() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("output base is zero")
public void testSecondBaseIsZero() {
BaseConverter baseConverter = new BaseConverter(10, new int[]{7});
@@ -176,6 +196,7 @@ public void testSecondBaseIsZero() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("output base is negative")
public void testSecondBaseIsNegative() {
BaseConverter baseConverter = new BaseConverter(2, new int[]{1});
diff --git a/exercises/practice/allergies/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/allergies/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/allergies/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/allergies/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/allergies/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/allergies/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/allergies/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/allergies/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/allergies/gradlew b/exercises/practice/allergies/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/allergies/gradlew
+++ b/exercises/practice/allergies/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/allergies/gradlew.bat b/exercises/practice/allergies/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/allergies/gradlew.bat
+++ b/exercises/practice/allergies/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/allergies/src/test/java/AllergiesTest.java b/exercises/practice/allergies/src/test/java/AllergiesTest.java
index 851b40656..cd0ae5cf7 100644
--- a/exercises/practice/allergies/src/test/java/AllergiesTest.java
+++ b/exercises/practice/allergies/src/test/java/AllergiesTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -9,6 +10,7 @@ public class AllergiesTest {
// Testing for eggs allergy
@Test
+ @DisplayName("not allergic to anything")
public void eggsNotAllergicToAnything() {
Allergies allergies = new Allergies(0);
@@ -17,6 +19,7 @@ public void eggsNotAllergicToAnything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic only to eggs")
public void eggsAllergicOnlyToEggs() {
Allergies allergies = new Allergies(1);
@@ -25,6 +28,7 @@ public void eggsAllergicOnlyToEggs() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to eggs and something else")
public void eggsAllergicToEggsAndSomethingElse() {
Allergies allergies = new Allergies(3);
@@ -33,6 +37,7 @@ public void eggsAllergicToEggsAndSomethingElse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to something, but not eggs")
public void eggsAllergicToSomethingButNotEggs() {
Allergies allergies = new Allergies(2);
@@ -41,6 +46,7 @@ public void eggsAllergicToSomethingButNotEggs() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to everything")
public void eggsAllergicToEverything() {
Allergies allergies = new Allergies(255);
@@ -51,6 +57,7 @@ public void eggsAllergicToEverything() {
// Testing for peanuts allergy
@Test
+ @DisplayName("not allergic to anything")
public void peanutsNotAllergicToAnything() {
Allergies allergies = new Allergies(0);
@@ -59,6 +66,7 @@ public void peanutsNotAllergicToAnything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic only to peanuts")
public void peanutsAllergicOnlyToPeanuts() {
Allergies allergies = new Allergies(2);
@@ -67,6 +75,7 @@ public void peanutsAllergicOnlyToPeanuts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to peanuts and something else")
public void peanutsAllergicToPeanutsAndSomethingElse() {
Allergies allergies = new Allergies(7);
@@ -75,6 +84,7 @@ public void peanutsAllergicToPeanutsAndSomethingElse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to something, but not peanuts")
public void peanutsAllergicToSomethingButNotPeanuts() {
Allergies allergies = new Allergies(5);
@@ -83,6 +93,7 @@ public void peanutsAllergicToSomethingButNotPeanuts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to everything")
public void peanutsAllergicToEverything() {
Allergies allergies = new Allergies(255);
@@ -93,6 +104,7 @@ public void peanutsAllergicToEverything() {
// Testing for shellfish allergy
@Test
+ @DisplayName("not allergic to anything")
public void shellfishNotAllergicToAnything() {
Allergies allergies = new Allergies(0);
@@ -101,6 +113,7 @@ public void shellfishNotAllergicToAnything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic only to shellfish")
public void shellfishAllergicOnlyToShellfish() {
Allergies allergies = new Allergies(4);
@@ -109,6 +122,7 @@ public void shellfishAllergicOnlyToShellfish() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to shellfish and something else")
public void shellfishAllergicToShellfishAndSomethingElse() {
Allergies allergies = new Allergies(14);
@@ -117,6 +131,7 @@ public void shellfishAllergicToShellfishAndSomethingElse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to something, but not shellfish")
public void shellfishAllergicToSomethingButNotShellfish() {
Allergies allergies = new Allergies(10);
@@ -125,6 +140,7 @@ public void shellfishAllergicToSomethingButNotShellfish() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to everything")
public void shellfishAllergicToEverything() {
Allergies allergies = new Allergies(255);
@@ -135,6 +151,7 @@ public void shellfishAllergicToEverything() {
// Testing for strawberries allergy
@Test
+ @DisplayName("not allergic to anything")
public void strawberriesNotAllergicToAnything() {
Allergies allergies = new Allergies(0);
@@ -143,6 +160,7 @@ public void strawberriesNotAllergicToAnything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic only to strawberries")
public void strawberriesAllergicOnlyToStrawberries() {
Allergies allergies = new Allergies(8);
@@ -151,6 +169,7 @@ public void strawberriesAllergicOnlyToStrawberries() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to strawberries and something else")
public void strawberriesAllergicToStrawberriesAndSomethingElse() {
Allergies allergies = new Allergies(28);
@@ -159,6 +178,7 @@ public void strawberriesAllergicToStrawberriesAndSomethingElse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to something, but not strawberries")
public void strawberriesAllergicToSomethingButNotStrawberries() {
Allergies allergies = new Allergies(20);
@@ -167,6 +187,7 @@ public void strawberriesAllergicToSomethingButNotStrawberries() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to everything")
public void strawberriesAllergicToEverything() {
Allergies allergies = new Allergies(255);
@@ -177,6 +198,7 @@ public void strawberriesAllergicToEverything() {
// Testing for tomatoes allergy
@Test
+ @DisplayName("not allergic to anything")
public void tomatoesNotAllergicToAnything() {
Allergies allergies = new Allergies(0);
@@ -185,6 +207,7 @@ public void tomatoesNotAllergicToAnything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic only to tomatoes")
public void tomatoesAllergicOnlyToTomatoes() {
Allergies allergies = new Allergies(16);
@@ -193,6 +216,7 @@ public void tomatoesAllergicOnlyToTomatoes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to tomatoes and something else")
public void tomatoesAllergicToTomatoesAndSomethingElse() {
Allergies allergies = new Allergies(56);
@@ -201,6 +225,7 @@ public void tomatoesAllergicToTomatoesAndSomethingElse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to something, but not tomatoes")
public void tomatoesAllergicToSomethingButNotTomatoes() {
Allergies allergies = new Allergies(40);
@@ -209,6 +234,7 @@ public void tomatoesAllergicToSomethingButNotTomatoes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to everything")
public void tomatoesAllergicToEverything() {
Allergies allergies = new Allergies(255);
@@ -219,6 +245,7 @@ public void tomatoesAllergicToEverything() {
// Testing for chocolate allergy
@Test
+ @DisplayName("not allergic to anything")
public void chocolateNotAllergicToAnything() {
Allergies allergies = new Allergies(0);
@@ -227,6 +254,7 @@ public void chocolateNotAllergicToAnything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic only to chocolate")
public void chocolateAllergicOnlyToChocolate() {
Allergies allergies = new Allergies(32);
@@ -235,6 +263,7 @@ public void chocolateAllergicOnlyToChocolate() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to chocolate and something else")
public void chocolateAllergicToChocolateAndSomethingElse() {
Allergies allergies = new Allergies(112);
@@ -243,6 +272,7 @@ public void chocolateAllergicToChocolateAndSomethingElse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to something, but not chocolate")
public void chocolateAllergicToSomethingButNotChocolate() {
Allergies allergies = new Allergies(80);
@@ -251,6 +281,7 @@ public void chocolateAllergicToSomethingButNotChocolate() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to everything")
public void chocolateAllergicToEverything() {
Allergies allergies = new Allergies(255);
@@ -261,6 +292,7 @@ public void chocolateAllergicToEverything() {
// Testing for pollen allergy
@Test
+ @DisplayName("not allergic to anything")
public void pollenNotAllergicToAnything() {
Allergies allergies = new Allergies(0);
@@ -269,6 +301,7 @@ public void pollenNotAllergicToAnything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic only to pollen")
public void pollenAllergicOnlyToPollen() {
Allergies allergies = new Allergies(64);
@@ -277,6 +310,7 @@ public void pollenAllergicOnlyToPollen() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to pollen and something else")
public void pollenAllergicToPollenAndSomethingElse() {
Allergies allergies = new Allergies(224);
@@ -285,6 +319,7 @@ public void pollenAllergicToPollenAndSomethingElse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to something, but not pollen")
public void pollenAllergicToSomethingButNotPollen() {
Allergies allergies = new Allergies(160);
@@ -293,6 +328,7 @@ public void pollenAllergicToSomethingButNotPollen() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to everything")
public void pollenAllergicToEverything() {
Allergies allergies = new Allergies(255);
@@ -303,6 +339,7 @@ public void pollenAllergicToEverything() {
// Testing for cats allergy
@Test
+ @DisplayName("not allergic to anything")
public void catsNotAllergicToAnything() {
Allergies allergies = new Allergies(0);
@@ -311,6 +348,7 @@ public void catsNotAllergicToAnything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic only to cats")
public void catsAllergicOnlyToCats() {
Allergies allergies = new Allergies(128);
@@ -319,6 +357,7 @@ public void catsAllergicOnlyToCats() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to cats and something else")
public void catsAllergicToCatsAndSomethingElse() {
Allergies allergies = new Allergies(192);
@@ -327,6 +366,7 @@ public void catsAllergicToCatsAndSomethingElse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to something, but not cats")
public void catsAllergicToSomethingButNotCats() {
Allergies allergies = new Allergies(64);
@@ -335,6 +375,7 @@ public void catsAllergicToSomethingButNotCats() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("allergic to everything")
public void catsAllergicToEverything() {
Allergies allergies = new Allergies(255);
@@ -346,6 +387,7 @@ public void catsAllergicToEverything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("no allergies")
public void listNoAllergies() {
Allergies allergies = new Allergies(0);
@@ -354,6 +396,7 @@ public void listNoAllergies() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("just eggs")
public void listJustEggs() {
Allergies allergies = new Allergies(1);
@@ -363,6 +406,7 @@ public void listJustEggs() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("just peanuts")
public void listJustPeanuts() {
Allergies allergies = new Allergies(2);
@@ -372,6 +416,7 @@ public void listJustPeanuts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("just strawberries")
public void listJustStrawberries() {
Allergies allergies = new Allergies(8);
@@ -381,6 +426,7 @@ public void listJustStrawberries() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("eggs and peanuts")
public void listEggsAndPeanuts() {
Allergies allergies = new Allergies(3);
@@ -392,6 +438,7 @@ public void listEggsAndPeanuts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("more than eggs but not peanuts")
public void listoMoreThanEggsButNotPeanuts() {
Allergies allergies = new Allergies(5);
@@ -403,6 +450,7 @@ public void listoMoreThanEggsButNotPeanuts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("lots of stuff")
public void listManyAllergies() {
Allergies allergies = new Allergies(248);
@@ -417,6 +465,7 @@ public void listManyAllergies() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("everything")
public void listEverything() {
Allergies allergies = new Allergies(255);
@@ -434,6 +483,7 @@ public void listEverything() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("no allergen score parts")
public void listNoAllergenScoreParts() {
Allergies allergies = new Allergies(509);
@@ -450,6 +500,7 @@ public void listNoAllergenScoreParts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("no allergen score parts without highest valid score")
public void listNoAllergenScorePartsWithoutHighestValidScore() {
Allergies allergies = new Allergies(257);
diff --git a/exercises/practice/alphametics/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/alphametics/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/alphametics/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/alphametics/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/alphametics/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/alphametics/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/alphametics/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/alphametics/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/alphametics/gradlew b/exercises/practice/alphametics/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/alphametics/gradlew
+++ b/exercises/practice/alphametics/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/alphametics/gradlew.bat b/exercises/practice/alphametics/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/alphametics/gradlew.bat
+++ b/exercises/practice/alphametics/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/alphametics/src/test/java/AlphameticsTest.java b/exercises/practice/alphametics/src/test/java/AlphameticsTest.java
index 93aef51be..8661a8de3 100644
--- a/exercises/practice/alphametics/src/test/java/AlphameticsTest.java
+++ b/exercises/practice/alphametics/src/test/java/AlphameticsTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static java.util.Map.entry;
@@ -8,6 +9,7 @@
public class AlphameticsTest {
@Test
+ @DisplayName("puzzle with three letters")
public void testThreeLetters() throws UnsolvablePuzzleException {
assertThat(new Alphametics("I + BB == ILL").solve())
.containsOnly(
@@ -18,6 +20,7 @@ public void testThreeLetters() throws UnsolvablePuzzleException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("solution must have unique value for each letter")
public void testUniqueValue() {
Alphametics alphametics = new Alphametics("A == B");
@@ -27,6 +30,7 @@ public void testUniqueValue() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("leading zero solution is invalid")
public void testLeadingZero() {
Alphametics alphametics = new Alphametics("ACA + DD == BD");
@@ -36,6 +40,7 @@ public void testLeadingZero() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("puzzle with two digits final carry")
public void testTwoDigitsFinalCarry() throws UnsolvablePuzzleException {
assertThat(new Alphametics("A + A + A + A + A + A + A + A + A + A + A + B == BCC").solve())
.containsOnly(
@@ -46,6 +51,7 @@ public void testTwoDigitsFinalCarry() throws UnsolvablePuzzleException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("puzzle with four letters")
public void testFourLetters() throws UnsolvablePuzzleException {
assertThat(new Alphametics("AS + A == MOM").solve())
.containsOnly(
@@ -57,6 +63,7 @@ public void testFourLetters() throws UnsolvablePuzzleException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("puzzle with six letters")
public void testSixLetters() throws UnsolvablePuzzleException {
assertThat(new Alphametics("NO + NO + TOO == LATE").solve())
.containsOnly(
@@ -70,6 +77,7 @@ public void testSixLetters() throws UnsolvablePuzzleException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("puzzle with seven letters")
public void testSevenLetters() throws UnsolvablePuzzleException {
assertThat(new Alphametics("HE + SEES + THE == LIGHT").solve())
.containsOnly(
@@ -84,6 +92,7 @@ public void testSevenLetters() throws UnsolvablePuzzleException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("puzzle with eight letters")
public void testEightLetters() throws UnsolvablePuzzleException {
assertThat(new Alphametics("SEND + MORE == MONEY").solve())
.containsOnly(
@@ -99,6 +108,7 @@ public void testEightLetters() throws UnsolvablePuzzleException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("puzzle with ten letters")
public void testTenLetters() throws UnsolvablePuzzleException {
assertThat(new Alphametics("AND + A + STRONG + OFFENSE + AS + A + GOOD == DEFENSE").solve())
.containsOnly(
@@ -116,7 +126,8 @@ public void testTenLetters() throws UnsolvablePuzzleException {
@Disabled("Remove to run test")
@Test
- public void testTenLetters41Addends() throws UnsolvablePuzzleException {
+ @DisplayName("puzzle with ten letters and 199 addends")
+ public void testTenLetters199Addends() throws UnsolvablePuzzleException {
assertThat(new Alphametics("THIS + A + FIRE + THEREFORE + FOR + ALL + HISTORIES + I + TELL + A + " +
"TALE + THAT + FALSIFIES + ITS + TITLE + TIS + A + LIE + THE + TALE + OF + THE + LAST + FIRE + " +
"HORSES + LATE + AFTER + THE + FIRST + FATHERS + FORESEE + THE + HORRORS + THE + LAST + FREE + " +
diff --git a/exercises/practice/anagram/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/anagram/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/anagram/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/anagram/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/anagram/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/anagram/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/anagram/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/anagram/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/anagram/gradlew b/exercises/practice/anagram/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/anagram/gradlew
+++ b/exercises/practice/anagram/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/anagram/gradlew.bat b/exercises/practice/anagram/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/anagram/gradlew.bat
+++ b/exercises/practice/anagram/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/anagram/src/test/java/AnagramTest.java b/exercises/practice/anagram/src/test/java/AnagramTest.java
index e5434291a..79a3a261b 100644
--- a/exercises/practice/anagram/src/test/java/AnagramTest.java
+++ b/exercises/practice/anagram/src/test/java/AnagramTest.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.Arrays;
@@ -9,6 +10,7 @@
public class AnagramTest {
@Test
+ @DisplayName("no matches")
public void testNoMatches() {
Anagram detector = new Anagram("diaper");
@@ -20,6 +22,7 @@ public void testNoMatches() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("detects two anagrams")
public void testDetectsTwoAnagrams() {
Anagram detector = new Anagram("solemn");
@@ -29,6 +32,7 @@ public void testDetectsTwoAnagrams() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("does not detect anagram subsets")
public void testEliminateAnagramSubsets() {
Anagram detector = new Anagram("good");
@@ -37,6 +41,7 @@ public void testEliminateAnagramSubsets() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("detects anagram")
public void testDetectLongerAnagram() {
Anagram detector = new Anagram("listen");
@@ -48,6 +53,7 @@ public void testDetectLongerAnagram() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("detects three anagrams")
public void testDetectMultipleAnagramsForLongerWord() {
Anagram detector = new Anagram("allergy");
assertThat(
@@ -64,6 +70,7 @@ public void testDetectMultipleAnagramsForLongerWord() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("detects multiple anagrams with different case")
public void testDetectsMultipleAnagramsWithDifferentCase() {
Anagram detector = new Anagram("nose");
@@ -73,6 +80,7 @@ public void testDetectsMultipleAnagramsWithDifferentCase() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("does not detect non-anagrams with identical checksum")
public void testEliminateAnagramsWithSameChecksum() {
Anagram detector = new Anagram("mass");
@@ -82,6 +90,7 @@ public void testEliminateAnagramsWithSameChecksum() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("detects anagrams case-insensitively")
public void testCaseInsensitiveWhenBothAnagramAndSubjectStartWithUpperCaseLetter() {
Anagram detector = new Anagram("Orchestra");
@@ -93,6 +102,7 @@ public void testCaseInsensitiveWhenBothAnagramAndSubjectStartWithUpperCaseLetter
@Disabled("Remove to run test")
@Test
+ @DisplayName("detects anagrams using case-insensitive subject")
public void testCaseInsensitiveWhenSubjectStartsWithUpperCaseLetter() {
Anagram detector = new Anagram("Orchestra");
@@ -104,6 +114,7 @@ public void testCaseInsensitiveWhenSubjectStartsWithUpperCaseLetter() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("detects anagrams using case-insensitive possible matches")
public void testCaseInsensitiveWhenAnagramStartsWithUpperCaseLetter() {
Anagram detector = new Anagram("orchestra");
@@ -115,6 +126,7 @@ public void testCaseInsensitiveWhenAnagramStartsWithUpperCaseLetter() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("does not detect an anagram if the original word is repeated")
public void testIdenticalWordRepeatedIsNotAnagram() {
Anagram detector = new Anagram("go");
@@ -124,6 +136,7 @@ public void testIdenticalWordRepeatedIsNotAnagram() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("anagrams must use all letters exactly once")
public void testAnagramMustUseAllLettersExactlyOnce() {
Anagram detector = new Anagram("tapper");
@@ -133,6 +146,7 @@ public void testAnagramMustUseAllLettersExactlyOnce() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("words are not anagrams of themselves")
public void testWordsAreNotAnagramsOfThemselvesCaseInsensitive() {
Anagram detector = new Anagram("BANANA");
@@ -142,6 +156,7 @@ public void testWordsAreNotAnagramsOfThemselvesCaseInsensitive() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("words are not anagrams of themselves even if letter case is partially different")
public void testWordsAreNotAnagramsOfThemselvesEvenIfLetterCaseIsPartiallyDifferent() {
Anagram detector = new Anagram("BANANA");
@@ -151,6 +166,7 @@ public void testWordsAreNotAnagramsOfThemselvesEvenIfLetterCaseIsPartiallyDiffer
@Disabled("Remove to run test")
@Test
+ @DisplayName("words are not anagrams of themselves even if letter case is completely different")
public void testWordsAreNotAnagramsOfThemselvesEvenIfLetterCaseIsCompletelyDifferent() {
Anagram detector = new Anagram("BANANA");
@@ -160,6 +176,7 @@ public void testWordsAreNotAnagramsOfThemselvesEvenIfLetterCaseIsCompletelyDiffe
@Disabled("Remove to run test")
@Test
+ @DisplayName("words other than themselves can be anagrams")
public void testWordsOtherThanThemselvesCanBeAnagrams() {
Anagram detector = new Anagram("LISTEN");
@@ -169,6 +186,7 @@ public void testWordsOtherThanThemselvesCanBeAnagrams() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("handles case of greek letters")
public void testHandlesCaseOfGreekLetters() {
Anagram detector = new Anagram("ΑΒΓ");
@@ -178,6 +196,7 @@ public void testHandlesCaseOfGreekLetters() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("different characters may have the same bytes")
public void testDifferentCharactersWithSameBytes() {
Anagram detector = new Anagram("a⬂");
diff --git a/exercises/practice/armstrong-numbers/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/armstrong-numbers/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/armstrong-numbers/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/armstrong-numbers/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/armstrong-numbers/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/armstrong-numbers/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/armstrong-numbers/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/armstrong-numbers/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/armstrong-numbers/gradlew b/exercises/practice/armstrong-numbers/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/armstrong-numbers/gradlew
+++ b/exercises/practice/armstrong-numbers/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/armstrong-numbers/gradlew.bat b/exercises/practice/armstrong-numbers/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/armstrong-numbers/gradlew.bat
+++ b/exercises/practice/armstrong-numbers/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/armstrong-numbers/src/test/java/ArmstrongNumbersTest.java b/exercises/practice/armstrong-numbers/src/test/java/ArmstrongNumbersTest.java
index ea08d7259..8977970dc 100644
--- a/exercises/practice/armstrong-numbers/src/test/java/ArmstrongNumbersTest.java
+++ b/exercises/practice/armstrong-numbers/src/test/java/ArmstrongNumbersTest.java
@@ -1,5 +1,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -14,6 +15,7 @@ public void setup() {
}
@Test
+ @DisplayName("Zero is an Armstrong number")
public void zeroIsArmstrongNumber() {
assertThat(armstrongNumbers.isArmstrongNumber(0))
.isTrue();
@@ -21,6 +23,7 @@ public void zeroIsArmstrongNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Single-digit numbers are Armstrong numbers")
public void singleDigitsAreArmstrongNumbers() {
assertThat(armstrongNumbers.isArmstrongNumber(5))
.isTrue();
@@ -28,6 +31,7 @@ public void singleDigitsAreArmstrongNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("There are no two-digit Armstrong numbers")
public void noTwoDigitArmstrongNumbers() {
assertThat(armstrongNumbers.isArmstrongNumber(10))
.isFalse();
@@ -35,6 +39,7 @@ public void noTwoDigitArmstrongNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Three-digit number that is an Armstrong number")
public void threeDigitNumberIsArmstrongNumber() {
assertThat(armstrongNumbers.isArmstrongNumber(153))
.isTrue();
@@ -42,6 +47,7 @@ public void threeDigitNumberIsArmstrongNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Three-digit number that is not an Armstrong number")
public void threeDigitNumberIsNotArmstrongNumber() {
assertThat(armstrongNumbers.isArmstrongNumber(100))
.isFalse();
@@ -49,6 +55,7 @@ public void threeDigitNumberIsNotArmstrongNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Four-digit number that is an Armstrong number")
public void fourDigitNumberIsArmstrongNumber() {
assertThat(armstrongNumbers.isArmstrongNumber(9474))
.isTrue();
@@ -56,6 +63,7 @@ public void fourDigitNumberIsArmstrongNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Four-digit number that is not an Armstrong number")
public void fourDigitNumberIsNotArmstrongNumber() {
assertThat(armstrongNumbers.isArmstrongNumber(9475))
.isFalse();
@@ -63,6 +71,7 @@ public void fourDigitNumberIsNotArmstrongNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Seven-digit number that is an Armstrong number")
public void sevenDigitNumberIsArmstrongNumber() {
assertThat(armstrongNumbers.isArmstrongNumber(9926315))
.isTrue();
@@ -70,6 +79,7 @@ public void sevenDigitNumberIsArmstrongNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Seven-digit number that is not an Armstrong number")
public void sevenDigitNumberIsNotArmstrongNumber() {
assertThat(armstrongNumbers.isArmstrongNumber(9926314))
.isFalse();
diff --git a/exercises/practice/atbash-cipher/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/atbash-cipher/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/atbash-cipher/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/atbash-cipher/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/atbash-cipher/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/atbash-cipher/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/atbash-cipher/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/atbash-cipher/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/atbash-cipher/gradlew b/exercises/practice/atbash-cipher/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/atbash-cipher/gradlew
+++ b/exercises/practice/atbash-cipher/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/atbash-cipher/gradlew.bat b/exercises/practice/atbash-cipher/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/atbash-cipher/gradlew.bat
+++ b/exercises/practice/atbash-cipher/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/atbash-cipher/src/test/java/AtbashTest.java b/exercises/practice/atbash-cipher/src/test/java/AtbashTest.java
index f656a69dc..c914f8b28 100644
--- a/exercises/practice/atbash-cipher/src/test/java/AtbashTest.java
+++ b/exercises/practice/atbash-cipher/src/test/java/AtbashTest.java
@@ -1,5 +1,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -14,36 +15,42 @@ public void setup() {
}
@Test
+ @DisplayName("encode yes")
public void testEncodeYes() {
assertThat(atbash.encode("yes")).isEqualTo("bvh");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode no")
public void testEncodeNo() {
assertThat(atbash.encode("no")).isEqualTo("ml");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode OMG")
public void testEncodeOmgInCapital() {
assertThat(atbash.encode("OMG")).isEqualTo("lnt");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode spaces")
public void testEncodeOmgWithSpaces() {
assertThat(atbash.encode("O M G")).isEqualTo("lnt");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode mindblowingly")
public void testEncodeMindBlowingly() {
assertThat(atbash.encode("mindblowingly")).isEqualTo("nrmwy oldrm tob");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode numbers")
public void testEncodeNumbers() {
assertThat(atbash.encode("Testing,1 2 3, testing."))
.isEqualTo("gvhgr mt123 gvhgr mt");
@@ -51,6 +58,7 @@ public void testEncodeNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode deep thought")
public void testEncodeDeepThought() {
assertThat(atbash.encode("Truth is fiction."))
.isEqualTo("gifgs rhurx grlm");
@@ -58,6 +66,7 @@ public void testEncodeDeepThought() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("encode all the letters")
public void testEncodeAllTheLetters() {
assertThat(atbash.encode("The quick brown fox jumps over the lazy dog."))
.isEqualTo("gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt");
@@ -65,12 +74,14 @@ public void testEncodeAllTheLetters() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode exercism")
public void testDecodeExercism() {
assertThat(atbash.decode("vcvix rhn")).isEqualTo("exercism");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode a sentence")
public void testDecodeASentence() {
assertThat(atbash.decode("zmlyh gzxov rhlug vmzhg vkkrm thglm v"))
.isEqualTo("anobstacleisoftenasteppingstone");
@@ -78,6 +89,7 @@ public void testDecodeASentence() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode numbers")
public void testDecodeNumbers() {
assertThat(atbash.decode("gvhgr mt123 gvhgr mt"))
.isEqualTo("testing123testing");
@@ -85,6 +97,7 @@ public void testDecodeNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode all the letters")
public void testDecodeAllTheLetters() {
assertThat(atbash.decode("gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"))
.isEqualTo("thequickbrownfoxjumpsoverthelazydog");
@@ -92,12 +105,14 @@ public void testDecodeAllTheLetters() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode with too many spaces")
public void testDecodeWithTooManySpaces() {
assertThat(atbash.decode("vc vix r hn")).isEqualTo("exercism");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("decode with no spaces")
public void testDecodeWithNoSpaces() {
assertThat(atbash.decode("zmlyhgzxovrhlugvmzhgvkkrmthglmv"))
.isEqualTo("anobstacleisoftenasteppingstone");
diff --git a/exercises/practice/baffling-birthdays/.docs/instructions.md b/exercises/practice/baffling-birthdays/.docs/instructions.md
new file mode 100644
index 000000000..a01ec8679
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/.docs/instructions.md
@@ -0,0 +1,23 @@
+# Instructions
+
+Your task is to estimate the birthday paradox's probabilities.
+
+To do this, you need to:
+
+- Generate random birthdates.
+- Check if a collection of randomly generated birthdates contains at least two with the same birthday.
+- Estimate the probability that at least two people in a group share the same birthday for different group sizes.
+
+~~~~exercism/note
+A birthdate includes the full date of birth (year, month, and day), whereas a birthday refers only to the month and day, which repeat each year.
+Two birthdates with the same month and day correspond to the same birthday.
+~~~~
+
+~~~~exercism/caution
+The birthday paradox assumes that:
+
+- There are 365 possible birthdays (no leap years).
+- Each birthday is equally likely (uniform distribution).
+
+Your implementation must follow these assumptions.
+~~~~
diff --git a/exercises/practice/baffling-birthdays/.docs/introduction.md b/exercises/practice/baffling-birthdays/.docs/introduction.md
new file mode 100644
index 000000000..97dabd1e6
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/.docs/introduction.md
@@ -0,0 +1,25 @@
+# Introduction
+
+Fresh out of college, you're throwing a huge party to celebrate with friends and family.
+Over 70 people have shown up, including your mildly eccentric Uncle Ted.
+
+In one of his usual antics, he bets you £100 that at least two people in the room share the same birthday.
+That sounds ridiculous — there are many more possible birthdays than there are guests, so you confidently accept.
+
+To your astonishment, after collecting the birthdays of just 32 guests, you've already found two guests that share the same birthday.
+Accepting your loss, you hand Uncle Ted his £100, but something feels off.
+
+The next day, curiosity gets the better of you.
+A quick web search leads you to the [birthday paradox][birthday-problem], which reveals that with just 23 people, the probability of a shared birthday exceeds 50%.
+
+Ah. So _that's_ why Uncle Ted was so confident.
+
+Determined to turn the tables, you start looking up other paradoxes; next time, _you'll_ be the one making the bets.
+
+~~~~exercism/note
+The birthday paradox is a [veridical paradox][veridical-paradox]: even though it feels wrong, it is actually true.
+
+[veridical-paradox]: https://en.wikipedia.org/wiki/Paradox#Quine's_classification
+~~~~
+
+[birthday-problem]: https://en.wikipedia.org/wiki/Birthday_problem
diff --git a/exercises/practice/baffling-birthdays/.meta/config.json b/exercises/practice/baffling-birthdays/.meta/config.json
new file mode 100644
index 000000000..6e401cb62
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/.meta/config.json
@@ -0,0 +1,22 @@
+{
+ "authors": [
+ "Baboushka"
+ ],
+ "files": {
+ "solution": [
+ "src/main/java/BafflingBirthdays.java"
+ ],
+ "test": [
+ "src/test/java/BafflingBirthdaysTest.java"
+ ],
+ "example": [
+ ".meta/src/reference/java/BafflingBirthdays.java"
+ ],
+ "invalidator": [
+ "build.gradle"
+ ]
+ },
+ "blurb": "Estimate the birthday paradox's probabilities.",
+ "source": "Erik Schierboom",
+ "source_url": "https://github.com/exercism/problem-specifications/pull/2539"
+}
diff --git a/exercises/practice/baffling-birthdays/.meta/src/reference/java/BafflingBirthdays.java b/exercises/practice/baffling-birthdays/.meta/src/reference/java/BafflingBirthdays.java
new file mode 100644
index 000000000..ef58bc2c0
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/.meta/src/reference/java/BafflingBirthdays.java
@@ -0,0 +1,48 @@
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+class BafflingBirthdays {
+ private static final int nonLeapYear = 2001;
+ private static final int daysInYear = 365;
+
+ boolean sharedBirthday(List birthdates) {
+ Set seen = new HashSet<>();
+ for (LocalDate birthdate : birthdates) {
+ if (!seen.add(birthdate.getMonth().toString() + birthdate.getDayOfMonth())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ List randomBirthdates(int groupSize) {
+ if (groupSize <= 0) {
+ return List.of();
+ }
+ List birthdates = new ArrayList<>(groupSize);
+ ThreadLocalRandom random = ThreadLocalRandom.current();
+ for (int i = 0; i < groupSize; i++) {
+ int dayOfYear = random.nextInt(1, daysInYear + 1);
+ birthdates.add(LocalDate.ofYearDay(nonLeapYear, dayOfYear));
+ }
+ return birthdates;
+ }
+
+ double estimatedProbabilityOfSharedBirthday(int groupSize) {
+ if (groupSize <= 1) {
+ return 0.0;
+ }
+ if (groupSize > daysInYear) {
+ return 100.0;
+ }
+ double probabilityNoSharedBirthday = 1.0;
+ for (int k = 0; k < groupSize; k++) {
+ probabilityNoSharedBirthday *= (daysInYear - k) / (double) daysInYear;
+ }
+ return (1 - probabilityNoSharedBirthday) * 100.0;
+ }
+}
diff --git a/exercises/practice/baffling-birthdays/.meta/tests.toml b/exercises/practice/baffling-birthdays/.meta/tests.toml
new file mode 100644
index 000000000..c76afb466
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/.meta/tests.toml
@@ -0,0 +1,61 @@
+# This is an auto-generated file.
+#
+# Regenerating this file via `configlet sync` will:
+# - Recreate every `description` key/value pair
+# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
+# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
+# - Preserve any other key/value pair
+#
+# As user-added comments (using the # character) will be removed when this file
+# is regenerated, comments can be added via a `comment` key.
+
+[716dcc2b-8fe4-4fc9-8c48-cbe70d8e6b67]
+description = "shared birthday -> one birthdate"
+
+[f7b3eb26-bcfc-4c1e-a2de-af07afc33f45]
+description = "shared birthday -> two birthdates with same year, month, and day"
+
+[7193409a-6e16-4bcb-b4cc-9ffe55f79b25]
+description = "shared birthday -> two birthdates with same year and month, but different day"
+
+[d04db648-121b-4b72-93e8-d7d2dced4495]
+description = "shared birthday -> two birthdates with same month and day, but different year"
+
+[3c8bd0f0-14c6-4d4c-975a-4c636bfdc233]
+description = "shared birthday -> two birthdates with same year, but different month and day"
+
+[df5daba6-0879-4480-883c-e855c99cdaa3]
+description = "shared birthday -> two birthdates with different year, month, and day"
+
+[0c17b220-cbb9-4bd7-872f-373044c7b406]
+description = "shared birthday -> multiple birthdates without shared birthday"
+
+[966d6b0b-5c0a-4b8c-bc2d-64939ada49f8]
+description = "shared birthday -> multiple birthdates with one shared birthday"
+
+[b7937d28-403b-4500-acce-4d9fe3a9620d]
+description = "shared birthday -> multiple birthdates with more than one shared birthday"
+
+[70b38cea-d234-4697-b146-7d130cd4ee12]
+description = "random birthdates -> generate requested number of birthdates"
+
+[d9d5b7d3-5fea-4752-b9c1-3fcd176d1b03]
+description = "random birthdates -> years are not leap years"
+
+[d1074327-f68c-4c8a-b0ff-e3730d0f0521]
+description = "random birthdates -> months are random"
+
+[7df706b3-c3f5-471d-9563-23a4d0577940]
+description = "random birthdates -> days are random"
+
+[89a462a4-4265-4912-9506-fb027913f221]
+description = "estimated probability of at least one shared birthday -> for one person"
+
+[ec31c787-0ebb-4548-970c-5dcb4eadfb5f]
+description = "estimated probability of at least one shared birthday -> among ten people"
+
+[b548afac-a451-46a3-9bb0-cb1f60c48e2f]
+description = "estimated probability of at least one shared birthday -> among twenty-three people"
+
+[e43e6b9d-d77b-4f6c-a960-0fc0129a0bc5]
+description = "estimated probability of at least one shared birthday -> among seventy people"
diff --git a/exercises/practice/baffling-birthdays/build.gradle b/exercises/practice/baffling-birthdays/build.gradle
new file mode 100644
index 000000000..d28f35dee
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/build.gradle
@@ -0,0 +1,25 @@
+plugins {
+ id "java"
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation platform("org.junit:junit-bom:5.10.0")
+ testImplementation "org.junit.jupiter:junit-jupiter"
+ testImplementation "org.assertj:assertj-core:3.25.1"
+
+ testRuntimeOnly "org.junit.platform:junit-platform-launcher"
+}
+
+test {
+ useJUnitPlatform()
+
+ testLogging {
+ exceptionFormat = "full"
+ showStandardStreams = true
+ events = ["passed", "failed", "skipped"]
+ }
+}
diff --git a/exercises/practice/baffling-birthdays/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/baffling-birthdays/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..f8e1ee312
Binary files /dev/null and b/exercises/practice/baffling-birthdays/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/baffling-birthdays/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/baffling-birthdays/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..4d97ea344
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/exercises/practice/baffling-birthdays/gradlew b/exercises/practice/baffling-birthdays/gradlew
new file mode 100644
index 000000000..adff685a0
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright © 2015 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/exercises/practice/baffling-birthdays/gradlew.bat b/exercises/practice/baffling-birthdays/gradlew.bat
new file mode 100644
index 000000000..c4bdd3ab8
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/gradlew.bat
@@ -0,0 +1,93 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/exercises/practice/baffling-birthdays/src/main/java/BafflingBirthdays.java b/exercises/practice/baffling-birthdays/src/main/java/BafflingBirthdays.java
new file mode 100644
index 000000000..5e1925081
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/src/main/java/BafflingBirthdays.java
@@ -0,0 +1,16 @@
+import java.time.LocalDate;
+import java.util.List;
+
+class BafflingBirthdays {
+ boolean sharedBirthday(List birthdates) {
+ throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
+ }
+
+ List randomBirthdates(int groupSize) {
+ throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
+ }
+
+ double estimatedProbabilityOfSharedBirthday(int groupSize) {
+ throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
+ }
+}
\ No newline at end of file
diff --git a/exercises/practice/baffling-birthdays/src/test/java/BafflingBirthdaysTest.java b/exercises/practice/baffling-birthdays/src/test/java/BafflingBirthdaysTest.java
new file mode 100644
index 000000000..0726301dc
--- /dev/null
+++ b/exercises/practice/baffling-birthdays/src/test/java/BafflingBirthdaysTest.java
@@ -0,0 +1,176 @@
+import java.time.LocalDate;
+import java.util.List;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static java.time.Month.APRIL;
+import static java.time.Month.AUGUST;
+import static java.time.Month.DECEMBER;
+import static java.time.Month.FEBRUARY;
+import static java.time.Month.JANUARY;
+import static java.time.Month.JULY;
+import static java.time.Month.MAY;
+import static java.time.Month.NOVEMBER;
+import static java.time.Month.OCTOBER;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.data.Offset.offset;
+
+public class BafflingBirthdaysTest {
+ private BafflingBirthdays birthdays = new BafflingBirthdays();
+
+ @Test
+ @DisplayName("one birthdate")
+ public void oneBirthdateTest() {
+ assertThat(birthdays.sharedBirthday(List.of(
+ LocalDate.of(2000, JANUARY, 1)
+ ))).isFalse();
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("two birthdates with same year, month, and day")
+ public void twoBirthdatesWithSameYearMonthAndDayTest() {
+ assertThat(birthdays.sharedBirthday(List.of(
+ LocalDate.of(2000, JANUARY, 1),
+ LocalDate.of(2000, JANUARY, 1)
+ ))).isTrue();
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("two birthdates with same year and month, but different day")
+ public void twoBirthdatesWithSameYearAndMonthButDifferentDayTest() {
+ assertThat(birthdays.sharedBirthday(List.of(
+ LocalDate.of(2012, MAY, 9),
+ LocalDate.of(2012, MAY, 17)
+ ))).isFalse();
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("two birthdates with same month and day, but different year")
+ public void twoBirthdatesWithSameMonthAndDayButDifferentYearTest() {
+ assertThat(birthdays.sharedBirthday(List.of(
+ LocalDate.of(1999, OCTOBER, 23),
+ LocalDate.of(1988, OCTOBER, 23)
+ ))).isTrue();
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("two birthdates with same year, but different month and day")
+ public void twoBirthdatesWithSameYearButDifferentMonthAndDayTest() {
+ assertThat(birthdays.sharedBirthday(List.of(
+ LocalDate.of(2007, DECEMBER, 19),
+ LocalDate.of(2007, APRIL, 27)
+ ))).isFalse();
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("two birthdates with different year, month, and day")
+ public void twoBirthdatesWithDifferentYearMonthAndDayTest() {
+ assertThat(birthdays.sharedBirthday(List.of(
+ LocalDate.of(1997, AUGUST, 4),
+ LocalDate.of(1963, NOVEMBER, 23)
+ ))).isFalse();
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("multiple birthdates without shared birthday")
+ public void multipleBirthdatesWithoutSharedBirthdayTest() {
+ assertThat(birthdays.sharedBirthday(List.of(
+ LocalDate.of(1966, AUGUST, 29),
+ LocalDate.of(1977, FEBRUARY, 12),
+ LocalDate.of(2001, DECEMBER, 25),
+ LocalDate.of(1980, NOVEMBER, 10)
+ ))).isFalse();
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("multiple birthdates with one shared birthday")
+ public void multipleBirthdatesWithOneSharedBirthdayTest() {
+ assertThat(birthdays.sharedBirthday(List.of(
+ LocalDate.of(1966, AUGUST, 29),
+ LocalDate.of(1977, FEBRUARY, 12),
+ LocalDate.of(2001, AUGUST, 29),
+ LocalDate.of(1980, NOVEMBER, 10)
+ ))).isTrue();
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("multiple birthdates with more than one shared birthday")
+ public void multipleBirthdatesWithMoreThanOneSharedBirthdayTest() {
+ assertThat(birthdays.sharedBirthday(List.of(
+ LocalDate.of(1966, JULY, 29),
+ LocalDate.of(1977, FEBRUARY, 12),
+ LocalDate.of(2001, DECEMBER, 25),
+ LocalDate.of(1980, JULY, 29),
+ LocalDate.of(2019, FEBRUARY, 12)
+ ))).isTrue();
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("generate requested number of birthdates")
+ public void generateRequestedNumberOfBirthdatesTest() {
+ int groupSize = 50;
+ assertThat(birthdays.randomBirthdates(groupSize).size()).isEqualTo(groupSize);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("years are not leap years")
+ public void yearsAreNotLeapYearsTest() {
+ assertThat(birthdays.randomBirthdates(100)).noneMatch(LocalDate::isLeapYear);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("months are random")
+ public void monthsAreRandomTest() {
+ assertThat(birthdays.randomBirthdates(500).stream().map(LocalDate::getMonth).distinct())
+ .hasSizeGreaterThanOrEqualTo(7);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("days are random")
+ public void daysAreRandomTest() {
+ assertThat(birthdays.randomBirthdates(500).stream().map(LocalDate::getDayOfMonth).distinct())
+ .hasSizeGreaterThanOrEqualTo(11);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("estimated probability of at least one shared birthday case for one person")
+ public void estimatedProbabilityOfAtLeastOneSharedBirthdayForOnePersonTest() {
+ assertThat(birthdays.estimatedProbabilityOfSharedBirthday(1)).isEqualTo(0.0);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("estimated probability of at least one shared birthday case among ten people")
+ public void estimatedProbabilityOfAtLeastOneSharedBirthdayAmongTenPeopleTest() {
+ assertThat(birthdays.estimatedProbabilityOfSharedBirthday(10)).isCloseTo(11.694818, offset(1.0));
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("estimated probability of at least one shared birthday case among twenty-three people")
+ public void estimatedProbabilityOfAtLeastOneSharedBirthdayAmongTwentyThreePeopleTest() {
+ assertThat(birthdays.estimatedProbabilityOfSharedBirthday(23)).isCloseTo(50.729723, offset(1.0));
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("estimated probability of at least one shared birthday case among seventy people")
+ public void estimatedProbabilityOfAtLeastOneSharedBirthdayAmongSeventyPeopleTest() {
+ assertThat(birthdays.estimatedProbabilityOfSharedBirthday(70)).isCloseTo(99.915958, offset(1.0));
+ }
+}
diff --git a/exercises/practice/bank-account/.approaches/config.json b/exercises/practice/bank-account/.approaches/config.json
new file mode 100644
index 000000000..1739dcd4a
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/config.json
@@ -0,0 +1,45 @@
+{
+ "introduction": {
+ "authors": [
+ "kahgoh"
+ ]
+ },
+ "approaches": [
+ {
+ "uuid": "78d753b0-aa58-43dc-83c0-9ea41496de84",
+ "slug": "synchronized-methods",
+ "title": "Synchronized methods",
+ "blurb": "Use synchronized methods to prevent methods from running simultaneously in different threads",
+ "authors": [
+ "kahgoh"
+ ]
+ },
+ {
+ "uuid": "5f3b0152-02eb-40d5-9104-5edc30b4447e",
+ "slug": "synchronized-statements",
+ "title": "Synchronized statements",
+ "blurb": "Use an object to prevent threads from running blocks of code at the same time",
+ "authors": [
+ "kahgoh"
+ ]
+ },
+ {
+ "uuid": "0acd6f2b-27d0-4ae6-9c22-22b0b2047039",
+ "slug": "reentrant-lock",
+ "title": "Reentrant lock",
+ "blurb": "Use an ReentrantLock to explicitly acquire and release locks",
+ "authors": [
+ "kahgoh"
+ ]
+ },
+ {
+ "uuid": "4ad42f88-f750-4af9-bbbd-d8b2dc5e8078",
+ "slug": "readwrite-lock",
+ "title": "Readwrite lock",
+ "blurb": "Use separate read and write locks to achieve greater concurrency",
+ "authors": [
+ "kahgoh"
+ ]
+ }
+ ]
+}
diff --git a/exercises/practice/bank-account/.approaches/introduction.md b/exercises/practice/bank-account/.approaches/introduction.md
new file mode 100644
index 000000000..ac8d3c506
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/introduction.md
@@ -0,0 +1,351 @@
+# Introduction
+
+In Bank Account, you are tasked with implementing a number of operations that can be performed on a bank account.
+However, these operations may be performed by multiple threads at the same time.
+
+## General guidance
+
+The key to solving Bank Account is to prevent an account from being updated from multiple threads at the same time.
+For example, consider an account that begins with $0.
+A $10 deposit is made twice.
+Each transaction starts a thread.
+If the threads happen to start simultaneously, they might both see the account starting $0.
+They each add $10 to this amount and update the account accordingly.
+In this case, each thread sets the amount to $10 even though the transaction was made twice.
+
+The problem here is that both threads saw that there was $0 in the account prior to adding the deposit.
+Instead, each thread needs to take turns to process the deposit for the account so that they can process the transaction one at a time.
+This way, the later thread can "see" the deposited amount from the first thread.
+
+## Approach: Synchronized methods
+
+```java
+class BankAccount {
+ private int balance = 0;
+ private boolean isClosed = true;
+
+ synchronized void open() throws BankAccountActionInvalidException {
+ if (!isClosed) {
+ throw new BankAccountActionInvalidException("Account already open");
+ }
+ isClosed = false;
+ balance = 0;
+ }
+
+ synchronized void close() throws BankAccountActionInvalidException {
+ if (isClosed) {
+ throw new BankAccountActionInvalidException("Account not open");
+ }
+ isClosed = true;
+ }
+
+ synchronized int getBalance() throws BankAccountActionInvalidException {
+ checkIfClosed();
+ return balance;
+ }
+
+ synchronized void deposit(int amount) throws BankAccountActionInvalidException {
+ checkIfClosed();
+ checkIfValidAmount(amount);
+
+ balance += amount;
+ }
+
+ synchronized void withdraw(int amount) throws BankAccountActionInvalidException {
+ checkIfClosed();
+ checkIfValidAmount(amount);
+ checkIfEnoughMoneyInAccount(amount);
+
+ balance -= amount;
+ }
+
+ private void checkIfValidAmount(int amount) throws BankAccountActionInvalidException {
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ }
+
+ private void checkIfEnoughMoneyInAccount(int amount) throws BankAccountActionInvalidException {
+ if (balance == 0) {
+ throw new BankAccountActionInvalidException("Cannot withdraw money from an empty account");
+ }
+ if (balance - amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot withdraw more money than is currently in the account");
+ }
+ }
+
+ private void checkIfClosed() throws BankAccountActionInvalidException {
+ if (isClosed) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ }
+}
+```
+
+For more information, check the [Synchronized methods approach][approach-synchronized-methods].
+
+## Approach: Synchronized statements
+
+```java
+class BankAccount {
+ private final Object lock = new Object();
+ private int balance = 0;
+ private boolean isClosed = true;
+
+ void open() throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ if (!isClosed) {
+ throw new BankAccountActionInvalidException("Account already open");
+ }
+ isClosed = false;
+ balance = 0;
+ }
+ }
+
+ void close() throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ if (isClosed) {
+ throw new BankAccountActionInvalidException("Account not open");
+ }
+ isClosed = true;
+ }
+ }
+
+ int getBalance() throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ checkIfClosed();
+ return balance;
+ }
+ }
+
+ void deposit(int amount) throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ checkIfClosed();
+ checkIfValidAmount(amount);
+
+ balance += amount;
+ }
+ }
+
+ void withdraw(int amount) throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ checkIfClosed();
+ checkIfValidAmount(amount);
+ checkIfEnoughMoneyInAccount(amount);
+
+ balance -= amount;
+ }
+ }
+
+ private void checkIfValidAmount(int amount) throws BankAccountActionInvalidException {
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ }
+
+ private void checkIfEnoughMoneyInAccount(int amount) throws BankAccountActionInvalidException {
+ if (balance == 0) {
+ throw new BankAccountActionInvalidException("Cannot withdraw money from an empty account");
+ }
+ if (balance - amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot withdraw more money than is currently in the account");
+ }
+ }
+
+ private void checkIfClosed() throws BankAccountActionInvalidException {
+ if (isClosed) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ }
+}
+```
+
+For more information, check the [Synchronized statements approach][approach-synchronized-statements].
+
+## Approach: Reentrant lock
+
+```java
+import java.util.concurrent.locks.ReentrantLock;
+
+class BankAccount {
+
+ private final ReentrantLock lock = new ReentrantLock();
+
+ private boolean isOpen = false;
+ private int balance = 0;
+
+ void open() throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (isOpen) {
+ throw new BankAccountActionInvalidException("Account already open");
+ }
+ isOpen = true;
+ balance = 0;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ void close() throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account not open");
+ }
+ isOpen = false;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ int getBalance() throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ return balance;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ void deposit(int amount) throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ balance += amount;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ void withdraw(int amount) throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ if (amount > balance) {
+ throw new BankAccountActionInvalidException("Cannot withdraw more money than is currently in the account");
+ }
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ balance -= amount;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+}
+```
+
+For more information, check the [Reentrant lock approach][approach-reentrant-lock].
+
+## Approach: Read write lock
+
+```java
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+class BankAccount {
+
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+ private boolean isOpen = false;
+
+ private int balance = 0;
+
+ void open() throws BankAccountActionInvalidException {
+ lock.writeLock().lock();
+ try {
+ if (isOpen) {
+ throw new BankAccountActionInvalidException("Account already open");
+ }
+ isOpen = true;
+ balance = 0;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ void close() throws BankAccountActionInvalidException {
+ lock.writeLock().lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account not open");
+ }
+ isOpen = false;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ int getBalance() throws BankAccountActionInvalidException {
+ lock.readLock().lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ return balance;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ void deposit(int amount) throws BankAccountActionInvalidException {
+ lock.writeLock().lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ balance += amount;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ void withdraw(int amount) throws BankAccountActionInvalidException {
+ lock.writeLock().lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ if (amount > balance) {
+ throw new BankAccountActionInvalidException("Cannot withdraw more money than is currently in the account");
+ }
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ balance -= amount;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+}
+```
+
+For more information, check the [Read write lock approach][approach-read-write-lock].
+
+## Which approach to use?
+
+- The synchronized methods is the simplest, requiring no extra objects to be created.
+- Synchronized statements provide greater control over which code statements are performed with a lock and which object is to be used as the lock.
+- The read write lock allows greater concurrency by letting multiple read operations, such as `getBalance`, run in parallel.
+ However, it requires the lock to be explicitly released.
+
+[approach-read-write-lock]: https://exercism.org/tracks/java/exercises/bank-account/approaches/readwrite-lock
+[approach-reentrant-lock]: https://exercism.org/tracks/java/exercises/bank-acconuunt/approaches/reentrant-lock
+[approach-synchronized-methods]: https://exercism.org/tracks/java/exercises/bank-account/approaches/synchronized-methods
+[approach-synchronized-statements]: https://exercism.org/tracks/java/exercises/bank-account/approaches/synchronzied-statements
diff --git a/exercises/practice/bank-account/.approaches/readwrite-lock/content.md b/exercises/practice/bank-account/.approaches/readwrite-lock/content.md
new file mode 100644
index 000000000..5db33cc0a
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/readwrite-lock/content.md
@@ -0,0 +1,108 @@
+# Readwrite Lock
+
+```java
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+class BankAccount {
+
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+ private boolean isOpen = false;
+
+ private int balance = 0;
+
+ void open() throws BankAccountActionInvalidException {
+ lock.writeLock().lock();
+ try {
+ if (isOpen) {
+ throw new BankAccountActionInvalidException("Account already open");
+ }
+ isOpen = true;
+ balance = 0;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ void close() throws BankAccountActionInvalidException {
+ lock.writeLock().lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account not open");
+ }
+ isOpen = false;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ int getBalance() throws BankAccountActionInvalidException {
+ lock.readLock().lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ return balance;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ void deposit(int amount) throws BankAccountActionInvalidException {
+ lock.writeLock().lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ balance += amount;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ void withdraw(int amount) throws BankAccountActionInvalidException {
+ lock.writeLock().lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ if (amount > balance) {
+ throw new BankAccountActionInvalidException("Cannot withdraw more money than is currently in the account");
+ }
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ balance -= amount;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+}
+```
+
+A [ReadWriteLock][docs-readwritelock] provides two types of locks - one for reading, the other for writing.
+[ReentrantReadWriteLock][docs-reentrantreadwritelock] is an implementation of a [ReadWriteLock][docs-readwritelock].
+
+Read locks are intended for read-only type operations, such as `getBalance`, and are acquired by calling `readLock().lock()` on the [ReadWriteLock][docs-readwritelock].
+Multiple threads are allowed to acquire read locks at the same time because they are expected to only read data.
+This means multiple threads can run `getBalance` at the same time.
+
+Write locks are for write operations, such as `withdraw` and `deposit`.
+It is also used in `open` and `close` as they change the state of the `BankAccount` (they "write" to the `isOpen` field).
+Write locks are acquired by calling `writeLock().lock()` on the [ReadWriteLock][docs-readwritelock].
+
+Only one thread can hold a write lock at a time.
+Therefore, `withdraw`, `deposit`, `open` and `close` can not run at the same time.
+Additionally, a thread must _also_ wait for _all_ read locks to be released to obtain a write lock.
+Similarly, threads must wait for write locks to be released before they are granted a read lock.
+This means `getBalance` also can not run at the same time as any of the `withdraw`, `deposit`, `open` and `close` methods.
+
+The locks are released in the `finally` block to ensure they are released, even when an exception is thrown.
+
+[docs-readwritelock]: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/locks/ReadWriteLock.html
+[docs-reentrantreadwritelock]: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/locks/ReentrantReadWriteLock.html
diff --git a/exercises/practice/bank-account/.approaches/readwrite-lock/snippet.txt b/exercises/practice/bank-account/.approaches/readwrite-lock/snippet.txt
new file mode 100644
index 000000000..45fcdf98d
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/readwrite-lock/snippet.txt
@@ -0,0 +1,7 @@
+private final ReadWriteLock lock = new ReentrantReadWriteLock();
+lock.readLock().lock();
+try {
+ balance += amount;
+} finally {
+ lock.readLock().unlock();
+}
\ No newline at end of file
diff --git a/exercises/practice/bank-account/.approaches/reentrant-lock/content.md b/exercises/practice/bank-account/.approaches/reentrant-lock/content.md
new file mode 100644
index 000000000..efa9f9512
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/reentrant-lock/content.md
@@ -0,0 +1,96 @@
+# Reentrant Lock
+
+```java
+import java.util.concurrent.locks.ReentrantLock;
+
+class BankAccount {
+
+ private final ReentrantLock lock = new ReentrantLock();
+
+ private boolean isOpen = false;
+ private int balance = 0;
+
+ void open() throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (isOpen) {
+ throw new BankAccountActionInvalidException("Account already open");
+ }
+ isOpen = true;
+ balance = 0;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ void close() throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account not open");
+ }
+ isOpen = false;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ int getBalance() throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ return balance;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ void deposit(int amount) throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ balance += amount;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ void withdraw(int amount) throws BankAccountActionInvalidException {
+ lock.lock();
+ try {
+ if (!isOpen) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ if (amount > balance) {
+ throw new BankAccountActionInvalidException("Cannot withdraw more money than is currently in the account");
+ }
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ balance -= amount;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+}
+```
+
+A [ReentrantLock][docs-reentrantlock] object represents a lock that threads must acquire to perform certain operations.
+It is used here by the operation methods to ensure they are not trying to update the bank account at the same time.
+
+The lock is requested by calling [lock][docs-reentrantlock-lock].
+The lock is released at the end of the operation by calling [unlock][docs-reentrantlock-unlock] in a `finally` block.
+This is important to ensure that the lock is released when it is no longer needed, especially if an exception is thrown.
+The re-entrant nature of the lock means a thread will be granted a lock again if it already has the lock.
+
+[docs-reentrantlock]: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/locks/ReentrantLock.html
+[docs-reentrantlock-lock]: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/locks/ReentrantLock.html#lock()
+[docs-reentrantlock-unlock]: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/locks/ReentrantLock.html#unlock()
diff --git a/exercises/practice/bank-account/.approaches/reentrant-lock/snippet.txt b/exercises/practice/bank-account/.approaches/reentrant-lock/snippet.txt
new file mode 100644
index 000000000..2014610f8
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/reentrant-lock/snippet.txt
@@ -0,0 +1,7 @@
+private final ReentrantLock lock = new ReentrantLock();
+lock.lock();
+try {
+ balance += amount;
+} finally {
+ lock.unlock();
+}
\ No newline at end of file
diff --git a/exercises/practice/bank-account/.approaches/synchronized-methods/content.md b/exercises/practice/bank-account/.approaches/synchronized-methods/content.md
new file mode 100644
index 000000000..7c1730694
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/synchronized-methods/content.md
@@ -0,0 +1,77 @@
+# Synchronized methods
+
+```java
+class BankAccount {
+ private int balance = 0;
+ private boolean isClosed = true;
+
+ synchronized void open() throws BankAccountActionInvalidException {
+ if (!isClosed) {
+ throw new BankAccountActionInvalidException("Account already open");
+ }
+ isClosed = false;
+ balance = 0;
+ }
+
+ synchronized void close() throws BankAccountActionInvalidException {
+ if (isClosed) {
+ throw new BankAccountActionInvalidException("Account not open");
+ }
+ isClosed = true;
+ }
+
+ synchronized int getBalance() throws BankAccountActionInvalidException {
+ checkIfClosed();
+ return balance;
+ }
+
+ synchronized void deposit(int amount) throws BankAccountActionInvalidException {
+ checkIfClosed();
+ checkIfValidAmount(amount);
+
+ balance += amount;
+ }
+
+ synchronized void withdraw(int amount) throws BankAccountActionInvalidException {
+ checkIfClosed();
+ checkIfValidAmount(amount);
+ checkIfEnoughMoneyInAccount(amount);
+
+ balance -= amount;
+ }
+
+ private void checkIfValidAmount(int amount) throws BankAccountActionInvalidException {
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ }
+
+ private void checkIfEnoughMoneyInAccount(int amount) throws BankAccountActionInvalidException {
+ if (balance == 0) {
+ throw new BankAccountActionInvalidException("Cannot withdraw money from an empty account");
+ }
+ if (balance - amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot withdraw more money than is currently in the account");
+ }
+ }
+
+ private void checkIfClosed() throws BankAccountActionInvalidException {
+ if (isClosed) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ }
+}
+```
+
+Each operation method is marked `synchronized`.
+This tells the thread to acquire a lock on the `BankAccount` object _before_ executing the method.
+If any other thread holds a lock on the `BankAccount` object, it must wait for the other thread to release the lock.
+
+~~~~exercism/note
+In Java, the is one other way to acquire a lock on the `BankAccount` object - [synchronized statements][approach-synchronized-statements].
+Since synchronized methods use a lock on the `BankAccount` object, it will also have to wait for locks on the `BankAccount` that are used by [synchronized statements][approach-synchronized-statements] to be reused.
+
+[approach-synchronized-statements]: https://exercism.org/tracks/java/exercises/bank-account/approaches/synchronzied-statements
+~~~~
+
+The lock is automatically released when the method finishes.
diff --git a/exercises/practice/bank-account/.approaches/synchronized-methods/snippet.txt b/exercises/practice/bank-account/.approaches/synchronized-methods/snippet.txt
new file mode 100644
index 000000000..61ca7d4ec
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/synchronized-methods/snippet.txt
@@ -0,0 +1,3 @@
+synchronized void deposit(int amount) throws BankAccountActionInvalidException {
+ balance += amount;
+}
\ No newline at end of file
diff --git a/exercises/practice/bank-account/.approaches/synchronized-statements/content.md b/exercises/practice/bank-account/.approaches/synchronized-statements/content.md
new file mode 100644
index 000000000..8d17806b1
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/synchronized-statements/content.md
@@ -0,0 +1,123 @@
+# Synchronized statements
+
+```java
+class BankAccount {
+ private final Object lock = new Object();
+ private int balance = 0;
+ private boolean isClosed = true;
+
+ void open() throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ if (!isClosed) {
+ throw new BankAccountActionInvalidException("Account already open");
+ }
+ isClosed = false;
+ balance = 0;
+ }
+ }
+
+ void close() throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ if (isClosed) {
+ throw new BankAccountActionInvalidException("Account not open");
+ }
+ isClosed = true;
+ }
+ }
+
+ int getBalance() throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ checkIfClosed();
+ return balance;
+ }
+ }
+
+ void deposit(int amount) throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ checkIfClosed();
+ checkIfValidAmount(amount);
+
+ balance += amount;
+ }
+ }
+
+ void withdraw(int amount) throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ checkIfClosed();
+ checkIfValidAmount(amount);
+ checkIfEnoughMoneyInAccount(amount);
+
+ balance -= amount;
+ }
+ }
+
+ private void checkIfValidAmount(int amount) throws BankAccountActionInvalidException {
+ if (amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot deposit or withdraw negative amount");
+ }
+ }
+
+ private void checkIfEnoughMoneyInAccount(int amount) throws BankAccountActionInvalidException {
+ if (balance == 0) {
+ throw new BankAccountActionInvalidException("Cannot withdraw money from an empty account");
+ }
+ if (balance - amount < 0) {
+ throw new BankAccountActionInvalidException("Cannot withdraw more money than is currently in the account");
+ }
+ }
+
+ private void checkIfClosed() throws BankAccountActionInvalidException {
+ if (isClosed) {
+ throw new BankAccountActionInvalidException("Account closed");
+ }
+ }
+}
+```
+
+In this approach, the operation methods, such as `open`, `close`, `deposit` and `withdraw`, perform their operations in a `synchronized` code block.
+A lock is acquired on the synchronized object (`lock`) before the statements inside the block are executed.
+If another thread has a lock on the object, it must wait for it to be released.
+The lock is released after the block is executed.
+
+## Using `this` as the synchronized object
+
+Any object can be used as the lock, including `this`.
+For example:
+
+```java
+int getBalance() throws BankAccountActionInvalidException {
+ synchronized(this) {
+ checkIfClosed();
+ return balance;
+ }
+}
+```
+
+This is the same as using a [synchronized method][approach-synchronized-methods], which requires a lock on the same `this` object to run the method.
+For example:
+
+```java
+synchronized int getBalance() throws BankAccountActionInvalidException {
+ checkIfClosed();
+ return balance;
+}
+```
+
+When using [synchronized methods][approach-synchronized-methods] and `synchronized(this)`, it is important to keep in mind that it may be trying to acquire a lock on the same instance.
+For example:
+
+```java
+BankAccount account = new BankAccount();
+
+Thread thread1 = new Thread(() -> {
+ account.withdraw(5);
+});
+
+Thread thread2 = new Thread(() -> {
+ synchronized (account) {
+ // Code in here can not run at same time as account.withdraw in thread1.
+ }
+});
+```
+
+[approach-synchronized-methods]: https://exercism.org/tracks/java/exercises/bank-account/approaches/synchronized-methods
diff --git a/exercises/practice/bank-account/.approaches/synchronized-statements/snippet.txt b/exercises/practice/bank-account/.approaches/synchronized-statements/snippet.txt
new file mode 100644
index 000000000..6b3a368fb
--- /dev/null
+++ b/exercises/practice/bank-account/.approaches/synchronized-statements/snippet.txt
@@ -0,0 +1,7 @@
+private final Object lock = new Object();
+
+void deposit(int amount) throws BankAccountActionInvalidException {
+ synchronized(lock) {
+ balance += amount;
+ }
+}
\ No newline at end of file
diff --git a/exercises/practice/bank-account/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/bank-account/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/bank-account/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/bank-account/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/bank-account/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/bank-account/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/bank-account/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/bank-account/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/bank-account/gradlew b/exercises/practice/bank-account/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/bank-account/gradlew
+++ b/exercises/practice/bank-account/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/bank-account/gradlew.bat b/exercises/practice/bank-account/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/bank-account/gradlew.bat
+++ b/exercises/practice/bank-account/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/bank-account/src/test/java/BankAccountTest.java b/exercises/practice/bank-account/src/test/java/BankAccountTest.java
index 35b4e04a0..8c6d65de7 100644
--- a/exercises/practice/bank-account/src/test/java/BankAccountTest.java
+++ b/exercises/practice/bank-account/src/test/java/BankAccountTest.java
@@ -1,5 +1,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.Random;
@@ -15,6 +16,7 @@ public void setUp() {
}
@Test
+ @DisplayName("Newly opened account has zero balance")
public void newlyOpenedAccountHasEmptyBalance() throws BankAccountActionInvalidException {
bankAccount.open();
@@ -23,6 +25,7 @@ public void newlyOpenedAccountHasEmptyBalance() throws BankAccountActionInvalidE
@Disabled("Remove to run test")
@Test
+ @DisplayName("Single deposit")
public void singleDeposit() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.deposit(100);
@@ -32,6 +35,7 @@ public void singleDeposit() throws BankAccountActionInvalidException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple deposits")
public void multipleDeposits() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.deposit(100);
@@ -42,6 +46,7 @@ public void multipleDeposits() throws BankAccountActionInvalidException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Withdraw once")
public void withdrawOnce() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.deposit(100);
@@ -52,6 +57,7 @@ public void withdrawOnce() throws BankAccountActionInvalidException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Withdraw twice")
public void withdrawTwice() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.deposit(100);
@@ -63,6 +69,7 @@ public void withdrawTwice() throws BankAccountActionInvalidException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Can do multiple operations sequentially")
public void canDoMultipleOperationsSequentially() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.deposit(100);
@@ -76,6 +83,7 @@ public void canDoMultipleOperationsSequentially() throws BankAccountActionInvali
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot check balance of closed account")
public void cannotCheckBalanceOfClosedAccount() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.close();
@@ -87,6 +95,7 @@ public void cannotCheckBalanceOfClosedAccount() throws BankAccountActionInvalidE
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot deposit into closed account")
public void cannotDepositIntoClosedAccount() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.close();
@@ -98,6 +107,7 @@ public void cannotDepositIntoClosedAccount() throws BankAccountActionInvalidExce
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot deposit into unopened account")
public void cannotDepositIntoUnopenedAccount() {
assertThatExceptionOfType(BankAccountActionInvalidException.class)
.isThrownBy(() -> bankAccount.deposit(50))
@@ -106,6 +116,7 @@ public void cannotDepositIntoUnopenedAccount() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot withdraw from closed account")
public void cannotWithdrawFromClosedAccount() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.close();
@@ -117,6 +128,7 @@ public void cannotWithdrawFromClosedAccount() throws BankAccountActionInvalidExc
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot close an account that was not opened")
public void cannotCloseAnAccountThatWasNotOpened() {
assertThatExceptionOfType(BankAccountActionInvalidException.class)
.isThrownBy(bankAccount::close)
@@ -125,6 +137,7 @@ public void cannotCloseAnAccountThatWasNotOpened() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot open an already opened account")
public void cannotOpenAnAlreadyOpenedAccount() throws BankAccountActionInvalidException {
bankAccount.open();
@@ -135,6 +148,7 @@ public void cannotOpenAnAlreadyOpenedAccount() throws BankAccountActionInvalidEx
@Disabled("Remove to run test")
@Test
+ @DisplayName("Reopened account does not retain balance")
public void reopenedAccountDoesNotRetainBalance() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.deposit(50);
@@ -146,7 +160,8 @@ public void reopenedAccountDoesNotRetainBalance() throws BankAccountActionInvali
@Disabled("Remove to run test")
@Test
- public void cannotWithdrawMoreThanWasDeposited() throws BankAccountActionInvalidException {
+ @DisplayName("Cannot withdraw more than deposited")
+ public void cannotWithdrawMoreThanDeposited() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.deposit(25);
@@ -157,6 +172,7 @@ public void cannotWithdrawMoreThanWasDeposited() throws BankAccountActionInvalid
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot withdraw negative")
public void cannotWithdrawNegativeAmount() throws BankAccountActionInvalidException {
bankAccount.open();
bankAccount.deposit(100);
@@ -168,6 +184,7 @@ public void cannotWithdrawNegativeAmount() throws BankAccountActionInvalidExcept
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot deposit negative")
public void cannotDepositNegativeAmount() throws BankAccountActionInvalidException {
bankAccount.open();
@@ -178,6 +195,7 @@ public void cannotDepositNegativeAmount() throws BankAccountActionInvalidExcepti
@Disabled("Remove to run test")
@Test
+ @DisplayName("Can handle concurrent transactions")
public void canHandleConcurrentTransactions() throws BankAccountActionInvalidException, InterruptedException {
bankAccount.open();
bankAccount.deposit(1000);
diff --git a/exercises/practice/binary-search-tree/.docs/instructions.md b/exercises/practice/binary-search-tree/.docs/instructions.md
index c9bbba5b9..7625220e9 100644
--- a/exercises/practice/binary-search-tree/.docs/instructions.md
+++ b/exercises/practice/binary-search-tree/.docs/instructions.md
@@ -19,29 +19,52 @@ All data in the left subtree is less than or equal to the current node's data, a
For example, if we had a node containing the data 4, and we added the data 2, our tree would look like this:
+
+
+```text
4
/
2
+```
If we then added 6, it would look like this:
+
+
+```text
4
/ \
2 6
+```
If we then added 3, it would look like this
+
+
+```text
4
/ \
2 6
\
3
+```
And if we then added 1, 5, and 7, it would look like this
+
+
+```text
4
/ \
/ \
2 6
/ \ / \
1 3 5 7
+```
+
+## Credit
+
+The images were created by [habere-et-dispertire][habere-et-dispertire] using [PGF/TikZ][pgf-tikz] by Till Tantau.
+
+[habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire
+[pgf-tikz]: https://en.wikipedia.org/wiki/PGF/TikZ
diff --git a/exercises/practice/binary-search-tree/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/binary-search-tree/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/binary-search-tree/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/binary-search-tree/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/binary-search-tree/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/binary-search-tree/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/binary-search-tree/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/binary-search-tree/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/binary-search-tree/gradlew b/exercises/practice/binary-search-tree/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/binary-search-tree/gradlew
+++ b/exercises/practice/binary-search-tree/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/binary-search-tree/gradlew.bat b/exercises/practice/binary-search-tree/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/binary-search-tree/gradlew.bat
+++ b/exercises/practice/binary-search-tree/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/binary-search-tree/src/test/java/BinarySearchTreeTest.java b/exercises/practice/binary-search-tree/src/test/java/BinarySearchTreeTest.java
index 1d16df93c..f6d8f1478 100644
--- a/exercises/practice/binary-search-tree/src/test/java/BinarySearchTreeTest.java
+++ b/exercises/practice/binary-search-tree/src/test/java/BinarySearchTreeTest.java
@@ -4,11 +4,13 @@
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class BinarySearchTreeTest {
@Test
+ @DisplayName("data is retained")
public void dataIsRetained() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
@@ -24,6 +26,7 @@ public void dataIsRetained() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("insert data at proper node")
public void insertsLess() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
@@ -45,6 +48,7 @@ public void insertsLess() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("same number at left node")
public void insertsSame() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
String expectedRoot = "4";
@@ -65,6 +69,7 @@ public void insertsSame() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("greater number at right node")
public void insertsRight() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
int expectedRoot = 4;
@@ -85,6 +90,7 @@ public void insertsRight() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can create complex tree")
public void createsComplexTree() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
List expected = List.of('4', '2', '6', '1', '3', '5', '7');
@@ -97,6 +103,7 @@ public void createsComplexTree() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can sort single number")
public void sortsSingleElement() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
List expected = Collections.singletonList("2");
@@ -108,6 +115,7 @@ public void sortsSingleElement() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can sort if second number is smaller than first")
public void sortsCollectionOfTwoIfSecondInsertedIsSmallerThanFirst() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
List expected = List.of(1, 2);
@@ -120,6 +128,7 @@ public void sortsCollectionOfTwoIfSecondInsertedIsSmallerThanFirst() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can sort if second number is same as first")
public void sortsCollectionOfTwoIfSecondNumberisSameAsFirst() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
List expected = List.of('2', '2');
@@ -132,6 +141,7 @@ public void sortsCollectionOfTwoIfSecondNumberisSameAsFirst() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can sort if second number is greater than first")
public void sortsCollectionOfTwoIfSecondInsertedIsBiggerThanFirst() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
List expected = List.of('2', '3');
@@ -144,6 +154,7 @@ public void sortsCollectionOfTwoIfSecondInsertedIsBiggerThanFirst() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can sort complex tree")
public void iteratesOverComplexTree() {
BinarySearchTree binarySearchTree = new BinarySearchTree<>();
List expected = List.of("1", "2", "3", "5", "6", "7");
diff --git a/exercises/practice/binary-search/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/binary-search/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/binary-search/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/binary-search/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/binary-search/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/binary-search/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/binary-search/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/binary-search/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/binary-search/gradlew b/exercises/practice/binary-search/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/binary-search/gradlew
+++ b/exercises/practice/binary-search/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/binary-search/gradlew.bat b/exercises/practice/binary-search/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/binary-search/gradlew.bat
+++ b/exercises/practice/binary-search/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/binary-search/src/test/java/BinarySearchTest.java b/exercises/practice/binary-search/src/test/java/BinarySearchTest.java
index f586f744c..4846489c9 100644
--- a/exercises/practice/binary-search/src/test/java/BinarySearchTest.java
+++ b/exercises/practice/binary-search/src/test/java/BinarySearchTest.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.Collections;
@@ -10,6 +11,7 @@
public class BinarySearchTest {
@Test
+ @DisplayName("finds a value in an array with one element")
public void findsAValueInAnArrayWithOneElement() throws ValueNotFoundException {
List listOfUnitLength = Collections.singletonList(6);
@@ -20,6 +22,7 @@ public void findsAValueInAnArrayWithOneElement() throws ValueNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("finds a value in the middle of an array")
public void findsAValueInTheMiddleOfAnArray() throws ValueNotFoundException {
List sortedList = List.of(1, 3, 4, 6, 8, 9, 11);
@@ -30,6 +33,7 @@ public void findsAValueInTheMiddleOfAnArray() throws ValueNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("finds a value at the beginning of an array")
public void findsAValueAtTheBeginningOfAnArray() throws ValueNotFoundException {
List sortedList = List.of(1, 3, 4, 6, 8, 9, 11);
@@ -40,6 +44,7 @@ public void findsAValueAtTheBeginningOfAnArray() throws ValueNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("finds a value at the end of an array")
public void findsAValueAtTheEndOfAnArray() throws ValueNotFoundException {
List sortedList = List.of(1, 3, 4, 6, 8, 9, 11);
@@ -50,6 +55,7 @@ public void findsAValueAtTheEndOfAnArray() throws ValueNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("finds a value in an array of odd length")
public void findsAValueInAnArrayOfOddLength() throws ValueNotFoundException {
List sortedListOfOddLength = List.of(1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634);
@@ -60,6 +66,7 @@ public void findsAValueInAnArrayOfOddLength() throws ValueNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("finds a value in an array of even length")
public void findsAValueInAnArrayOfEvenLength() throws ValueNotFoundException {
List sortedListOfEvenLength = List.of(1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377);
@@ -70,6 +77,7 @@ public void findsAValueInAnArrayOfEvenLength() throws ValueNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("identifies that a value is not included in the array")
public void identifiesThatAValueIsNotFoundInTheArray() {
List sortedList = List.of(1, 3, 4, 6, 8, 9, 11);
@@ -82,6 +90,7 @@ public void identifiesThatAValueIsNotFoundInTheArray() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a value smaller than the array's smallest value is not found")
public void aValueSmallerThanTheArraysSmallestValueIsNotFound() {
List sortedList = List.of(1, 3, 4, 6, 8, 9, 11);
@@ -94,6 +103,7 @@ public void aValueSmallerThanTheArraysSmallestValueIsNotFound() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a value larger than the array's largest value is not found")
public void aValueLargerThanTheArraysLargestValueIsNotFound() throws ValueNotFoundException {
List sortedList = List.of(1, 3, 4, 6, 8, 9, 11);
@@ -106,6 +116,7 @@ public void aValueLargerThanTheArraysLargestValueIsNotFound() throws ValueNotFou
@Disabled("Remove to run test")
@Test
+ @DisplayName("nothing is found in an empty array")
public void nothingIsFoundInAnEmptyArray() throws ValueNotFoundException {
List emptyList = Collections.emptyList();
@@ -118,6 +129,7 @@ public void nothingIsFoundInAnEmptyArray() throws ValueNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("nothing is found when the left and right bounds cross")
public void nothingIsFoundWhenTheLeftAndRightBoundCross() throws ValueNotFoundException {
List sortedList = List.of(1, 2);
diff --git a/exercises/practice/bob/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/bob/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/bob/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/bob/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/bob/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/bob/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/bob/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/bob/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/bob/gradlew b/exercises/practice/bob/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/bob/gradlew
+++ b/exercises/practice/bob/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/bob/gradlew.bat b/exercises/practice/bob/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/bob/gradlew.bat
+++ b/exercises/practice/bob/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/bob/src/test/java/BobTest.java b/exercises/practice/bob/src/test/java/BobTest.java
index 801315b42..756fb93f8 100644
--- a/exercises/practice/bob/src/test/java/BobTest.java
+++ b/exercises/practice/bob/src/test/java/BobTest.java
@@ -1,5 +1,6 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.BeforeEach;
import static org.assertj.core.api.Assertions.assertThat;
@@ -14,6 +15,7 @@ public void setUp() {
}
@Test
+ @DisplayName("stating something")
public void saySomething() {
assertThat(bob.hey("Tom-ay-to, tom-aaaah-to."))
.isEqualTo("Whatever.");
@@ -21,6 +23,7 @@ public void saySomething() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("shouting")
public void shouting() {
assertThat(bob.hey("WATCH OUT!"))
.isEqualTo("Whoa, chill out!");
@@ -28,6 +31,7 @@ public void shouting() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("shouting gibberish")
public void shoutingGibberish() {
assertThat(bob.hey("FCECDFCAAB"))
.isEqualTo("Whoa, chill out!");
@@ -35,6 +39,7 @@ public void shoutingGibberish() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("asking a question")
public void askingAQuestion() {
assertThat(bob.hey("Does this cryogenic chamber make me look fat?"))
.isEqualTo("Sure.");
@@ -42,6 +47,7 @@ public void askingAQuestion() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("asking a numeric question")
public void askingANumericQuestion() {
assertThat(bob.hey("You are, what, like 15?"))
.isEqualTo("Sure.");
@@ -49,6 +55,7 @@ public void askingANumericQuestion() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("asking gibberish")
public void askingGibberish() {
assertThat(bob.hey("fffbbcbeab?"))
.isEqualTo("Sure.");
@@ -56,6 +63,7 @@ public void askingGibberish() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("talking forcefully")
public void talkingForcefully() {
assertThat(bob.hey("Hi there!"))
.isEqualTo("Whatever.");
@@ -63,6 +71,7 @@ public void talkingForcefully() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("using acronyms in regular speech")
public void usingAcronymsInRegularSpeech() {
assertThat(bob.hey("It's OK if you don't want to go work for NASA."))
.isEqualTo("Whatever.");
@@ -70,6 +79,7 @@ public void usingAcronymsInRegularSpeech() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("forceful question")
public void forcefulQuestions() {
assertThat(bob.hey("WHAT'S GOING ON?"))
.isEqualTo("Calm down, I know what I'm doing!");
@@ -77,6 +87,7 @@ public void forcefulQuestions() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("shouting numbers")
public void shoutingNumbers() {
assertThat(bob.hey("1, 2, 3 GO!"))
.isEqualTo("Whoa, chill out!");
@@ -84,6 +95,7 @@ public void shoutingNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("no letters")
public void onlyNumbers() {
assertThat(bob.hey("1, 2, 3"))
.isEqualTo("Whatever.");
@@ -91,6 +103,7 @@ public void onlyNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("question with no letters")
public void questionWithOnlyNumbers() {
assertThat(bob.hey("4?"))
.isEqualTo("Sure.");
@@ -98,6 +111,7 @@ public void questionWithOnlyNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("shouting with special characters")
public void shoutingWithSpecialCharacters() {
assertThat(bob.hey("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!"))
.isEqualTo("Whoa, chill out!");
@@ -105,6 +119,7 @@ public void shoutingWithSpecialCharacters() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("shouting with no exclamation mark")
public void shoutingWithNoExclamationMark() {
assertThat(bob.hey("I HATE THE DENTIST"))
.isEqualTo("Whoa, chill out!");
@@ -112,6 +127,7 @@ public void shoutingWithNoExclamationMark() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("statement containing question mark")
public void statementContainingQuestionMark() {
assertThat(bob.hey("Ending with ? means a question."))
.isEqualTo("Whatever.");
@@ -119,6 +135,7 @@ public void statementContainingQuestionMark() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("non-letters with question")
public void nonLettersWithQuestion() {
assertThat(bob.hey(":) ?"))
.isEqualTo("Sure.");
@@ -126,6 +143,7 @@ public void nonLettersWithQuestion() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("prattling on")
public void prattlingOn() {
assertThat(bob.hey("Wait! Hang on. Are you going to be OK?"))
.isEqualTo("Sure.");
@@ -133,6 +151,7 @@ public void prattlingOn() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("silence")
public void silence() {
assertThat(bob.hey(""))
.isEqualTo("Fine. Be that way!");
@@ -140,6 +159,7 @@ public void silence() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("prolonged silence")
public void prolongedSilence() {
assertThat(bob.hey(" "))
.isEqualTo("Fine. Be that way!");
@@ -147,6 +167,7 @@ public void prolongedSilence() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("alternate silence")
public void alternateSilence() {
assertThat(bob.hey("\t\t\t\t\t\t\t\t\t\t"))
.isEqualTo("Fine. Be that way!");
@@ -154,6 +175,7 @@ public void alternateSilence() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("starting with whitespace")
public void startingWithWhitespace() {
assertThat(bob.hey(" hmmmmmmm..."))
.isEqualTo("Whatever.");
@@ -161,6 +183,7 @@ public void startingWithWhitespace() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("ending with whitespace")
public void endingWithWhiteSpace() {
assertThat(bob.hey("Okay if like my spacebar quite a bit? "))
.isEqualTo("Sure.");
@@ -168,6 +191,7 @@ public void endingWithWhiteSpace() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("other whitespace")
public void otherWhiteSpace() {
assertThat(bob.hey("\n\r \t"))
.isEqualTo("Fine. Be that way!");
@@ -175,6 +199,7 @@ public void otherWhiteSpace() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("non-question ending with whitespace")
public void nonQuestionEndingWithWhiteSpace() {
assertThat(bob.hey("This is a statement ending with whitespace "))
.isEqualTo("Whatever.");
@@ -182,6 +207,7 @@ public void nonQuestionEndingWithWhiteSpace() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("multiple line question")
public void multipleLineQuestion() {
assertThat(bob.hey("\nDoes this cryogenic chamber make\n me look fat?"))
.isEqualTo("Sure.");
diff --git a/exercises/practice/book-store/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/book-store/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/book-store/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/book-store/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/book-store/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/book-store/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/book-store/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/book-store/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/book-store/gradlew b/exercises/practice/book-store/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/book-store/gradlew
+++ b/exercises/practice/book-store/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/book-store/gradlew.bat b/exercises/practice/book-store/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/book-store/gradlew.bat
+++ b/exercises/practice/book-store/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/book-store/src/test/java/BookStoreTest.java b/exercises/practice/book-store/src/test/java/BookStoreTest.java
index 920b83658..bbcbbcfb9 100644
--- a/exercises/practice/book-store/src/test/java/BookStoreTest.java
+++ b/exercises/practice/book-store/src/test/java/BookStoreTest.java
@@ -1,6 +1,7 @@
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
@@ -23,6 +24,7 @@ public void setUp() {
}
@Test
+ @DisplayName("Only a single book")
public void onlyASingleBook() {
List books = Collections.singletonList(1);
assertThat(bookStore.calculateBasketCost(books))
@@ -31,6 +33,7 @@ public void onlyASingleBook() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Two of the same book")
public void twoOfSameBook() {
List books = Arrays.asList(2, 2);
assertThat(bookStore.calculateBasketCost(books))
@@ -39,6 +42,7 @@ public void twoOfSameBook() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Empty basket")
public void emptyBasket() {
List books = Collections.emptyList();
assertThat(bookStore.calculateBasketCost(books))
@@ -47,6 +51,7 @@ public void emptyBasket() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Two different books")
public void twoDifferentBooks() {
List books = Arrays.asList(1, 2);
assertThat(bookStore.calculateBasketCost(books))
@@ -55,6 +60,7 @@ public void twoDifferentBooks() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Three different books")
public void threeDifferentBooks() {
List books = Arrays.asList(1, 2, 3);
assertThat(bookStore.calculateBasketCost(books))
@@ -63,6 +69,7 @@ public void threeDifferentBooks() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Four different books")
public void fourDifferentBooks() {
List books = Arrays.asList(1, 2, 3, 4);
assertThat(bookStore.calculateBasketCost(books))
@@ -71,6 +78,7 @@ public void fourDifferentBooks() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Five different books")
public void fiveDifferentBooks() {
List books = Arrays.asList(1, 2, 3, 4, 5);
assertThat(bookStore.calculateBasketCost(books))
@@ -79,6 +87,7 @@ public void fiveDifferentBooks() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Two groups of four is cheaper than group of five plus group of three")
public void twoGroupsOfFourIsCheaperThanGroupOfFivePlusGroupOfThree() {
List books = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 5);
assertThat(bookStore.calculateBasketCost(books))
@@ -87,6 +96,7 @@ public void twoGroupsOfFourIsCheaperThanGroupOfFivePlusGroupOfThree() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Two groups of four is cheaper than groups of five and three")
public void twoGroupsOfFourIsCheaperThanGroupsOfFiveAndThree() {
List books = Arrays.asList(1, 1, 2, 3, 4, 4, 5, 5);
assertThat(bookStore.calculateBasketCost(books))
@@ -95,6 +105,7 @@ public void twoGroupsOfFourIsCheaperThanGroupsOfFiveAndThree() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Group of four plus group of two is cheaper than two groups of three")
public void groupOfFourPlusGroupOfTwoIsCheaperThanTwoGroupsOfThree() {
List books = Arrays.asList(1, 1, 2, 2, 3, 4);
assertThat(bookStore.calculateBasketCost(books))
@@ -103,6 +114,7 @@ public void groupOfFourPlusGroupOfTwoIsCheaperThanTwoGroupsOfThree() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Two each of first four books and one copy each of rest")
public void twoEachOfFirst4BooksAnd1CopyEachOfRest() {
List books = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4, 5);
assertThat(bookStore.calculateBasketCost(books))
@@ -111,6 +123,7 @@ public void twoEachOfFirst4BooksAnd1CopyEachOfRest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Two copies of each book")
public void twoCopiesOfEachBook() {
List books = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4, 5, 5);
assertThat(bookStore.calculateBasketCost(books))
@@ -119,7 +132,8 @@ public void twoCopiesOfEachBook() {
@Disabled("Remove to run test")
@Test
- public void threeCopiesOfFirstBookAnd2EachOfRemaining() {
+ @DisplayName("Three copies of first book and two each of remaining")
+ public void threeCopiesOfFirstBookAndTwoEachOfRemaining() {
List books = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 1);
assertThat(bookStore.calculateBasketCost(books))
.isCloseTo(68.00, Assertions.offset(EQUALITY_TOLERANCE));
@@ -127,7 +141,8 @@ public void threeCopiesOfFirstBookAnd2EachOfRemaining() {
@Disabled("Remove to run test")
@Test
- public void threeEachOFirst2BooksAnd2EachOfRemainingBooks() {
+ @DisplayName("Three each of first two books and two each of remaining books")
+ public void threeEachOfFirstTwoBooksAndTwoEachOfRemainingBooks() {
List books = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 1, 2);
assertThat(bookStore.calculateBasketCost(books))
.isCloseTo(75.20, Assertions.offset(EQUALITY_TOLERANCE));
@@ -135,6 +150,7 @@ public void threeEachOFirst2BooksAnd2EachOfRemainingBooks() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Four groups of four are cheaper than two groups each of five and three")
public void fourGroupsOfFourAreCheaperThanTwoGroupsEachOfFiveAndThree() {
List books = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 5, 1, 1, 2, 2, 3, 3, 4, 5);
assertThat(bookStore.calculateBasketCost(books))
@@ -143,6 +159,9 @@ public void fourGroupsOfFourAreCheaperThanTwoGroupsEachOfFiveAndThree() {
@Disabled("Remove to run test")
@Test
+ @DisplayName(
+ "Check that groups of four are created properly even when there are more groups of three than groups of five"
+ )
public void groupsOfFourAreCreatedEvenWhenThereAreMoreGroupsOfThreeThanGroupsOfFive() {
List books = Arrays.asList(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5);
assertThat(bookStore.calculateBasketCost(books))
@@ -151,6 +170,7 @@ public void groupsOfFourAreCreatedEvenWhenThereAreMoreGroupsOfThreeThanGroupsOfF
@Disabled("Remove to run test")
@Test
+ @DisplayName("One group of one and four is cheaper than one group of two and three")
public void oneGroupOfOneAndFourIsCheaperThanOneGroupOfTwoAndThree() {
List books = Arrays.asList(1, 1, 2, 3, 4);
assertThat(bookStore.calculateBasketCost(books))
@@ -159,6 +179,7 @@ public void oneGroupOfOneAndFourIsCheaperThanOneGroupOfTwoAndThree() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One group of one and two plus three groups of four is cheaper than one group of each size")
public void oneGroupOfOneAndTwoPlusThreeGroupsOfFourIsCheaperThanOneGroupOfEachSize() {
List books = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5);
assertThat(bookStore.calculateBasketCost(books))
diff --git a/exercises/practice/bottle-song/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/bottle-song/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/bottle-song/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/bottle-song/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/bottle-song/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/bottle-song/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/bottle-song/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/bottle-song/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/bottle-song/gradlew b/exercises/practice/bottle-song/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/bottle-song/gradlew
+++ b/exercises/practice/bottle-song/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/bottle-song/gradlew.bat b/exercises/practice/bottle-song/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/bottle-song/gradlew.bat
+++ b/exercises/practice/bottle-song/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/bottle-song/src/test/java/BottleSongTest.java b/exercises/practice/bottle-song/src/test/java/BottleSongTest.java
index a47a7edc8..7d5ce0a97 100644
--- a/exercises/practice/bottle-song/src/test/java/BottleSongTest.java
+++ b/exercises/practice/bottle-song/src/test/java/BottleSongTest.java
@@ -1,6 +1,7 @@
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -14,6 +15,7 @@ public void setup() {
}
@Test
+ @DisplayName("first generic verse")
public void firstGenericVerse() {
assertThat(bottleSong.recite(10, 1)).isEqualTo(
"Ten green bottles hanging on the wall,\n" +
@@ -25,6 +27,7 @@ public void firstGenericVerse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("last generic verse")
public void lastGenericVerse() {
assertThat(bottleSong.recite(3, 1)).isEqualTo(
"Three green bottles hanging on the wall,\n" +
@@ -36,6 +39,7 @@ public void lastGenericVerse() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("verse with 2 bottles")
public void verseWithTwoBottles() {
assertThat(bottleSong.recite(2, 1)).isEqualTo(
"Two green bottles hanging on the wall,\n" +
@@ -47,6 +51,7 @@ public void verseWithTwoBottles() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("verse with 1 bottle")
public void verseWithOneBottle() {
assertThat(bottleSong.recite(1, 1)).isEqualTo(
"One green bottle hanging on the wall,\n" +
@@ -58,6 +63,7 @@ public void verseWithOneBottle() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("first two verses")
public void firstTwoVerses() {
assertThat(bottleSong.recite(10, 2)).isEqualTo(
"Ten green bottles hanging on the wall,\n" +
@@ -74,6 +80,7 @@ public void firstTwoVerses() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("last three verses")
public void lastThreeVerses() {
assertThat(bottleSong.recite(3, 3)).isEqualTo(
"Three green bottles hanging on the wall,\n" +
@@ -95,6 +102,7 @@ public void lastThreeVerses() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("all verses")
public void allVerses() {
assertThat(bottleSong.recite(10, 10))
.isEqualTo(
diff --git a/exercises/practice/bowling/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/bowling/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/bowling/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/bowling/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/bowling/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/bowling/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/bowling/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/bowling/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/bowling/gradlew b/exercises/practice/bowling/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/bowling/gradlew
+++ b/exercises/practice/bowling/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/bowling/gradlew.bat b/exercises/practice/bowling/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/bowling/gradlew.bat
+++ b/exercises/practice/bowling/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/bowling/src/test/java/BowlingGameTest.java b/exercises/practice/bowling/src/test/java/BowlingGameTest.java
index 7b63a4fc1..a8fbcad96 100644
--- a/exercises/practice/bowling/src/test/java/BowlingGameTest.java
+++ b/exercises/practice/bowling/src/test/java/BowlingGameTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -14,6 +15,7 @@ private void playGame(int[] rolls) {
}
@Test
+ @DisplayName("should be able to score a game with all zeros")
public void shouldBeAbleToScoreAGameWithAllZeros() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -23,6 +25,7 @@ public void shouldBeAbleToScoreAGameWithAllZeros() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("should be able to score a game with no strikes or spares")
public void shouldBeAbleToScoreAGameWithNoStrikesOrSpares() {
int[] rolls = {3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6};
@@ -32,6 +35,7 @@ public void shouldBeAbleToScoreAGameWithNoStrikesOrSpares() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a spare followed by zeros is worth ten points")
public void aSpareFollowedByZerosIsWorthTenPoints() {
int[] rolls = {6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -41,6 +45,7 @@ public void aSpareFollowedByZerosIsWorthTenPoints() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("points scored in the roll after a spare are counted twice")
public void pointsScoredInTheRollAfterASpareAreCountedTwice() {
int[] rolls = {6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -50,6 +55,7 @@ public void pointsScoredInTheRollAfterASpareAreCountedTwice() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("consecutive spares each get a one roll bonus")
public void consecutiveSparesEachGetAOneRollBonus() {
int[] rolls = {5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -59,6 +65,7 @@ public void consecutiveSparesEachGetAOneRollBonus() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a spare in the last frame gets a one roll bonus that is counted once")
public void aSpareInTheLastFrameGetsAOneRollBonusThatIsCountedOnce() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7};
@@ -68,6 +75,7 @@ public void aSpareInTheLastFrameGetsAOneRollBonusThatIsCountedOnce() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a strike earns ten points in a frame with a single roll")
public void aStrikeEarnsTenPointsInFrameWithASingleRoll() {
int[] rolls = {10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -77,6 +85,7 @@ public void aStrikeEarnsTenPointsInFrameWithASingleRoll() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("points scored in the two rolls after a strike are counted twice as a bonus")
public void pointsScoredInTheTwoRollsAfterAStrikeAreCountedTwiceAsABonus() {
int[] rolls = {10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -86,6 +95,7 @@ public void pointsScoredInTheTwoRollsAfterAStrikeAreCountedTwiceAsABonus() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("consecutive strikes each get the two roll bonus")
public void consecutiveStrikesEachGetTheTwoRollBonus() {
int[] rolls = {10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -95,6 +105,7 @@ public void consecutiveStrikesEachGetTheTwoRollBonus() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a strike in the last frame gets a two roll bonus that is counted once")
public void aStrikeInTheLastFrameGetsATwoRollBonusThatIsCountedOnce() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1};
@@ -104,6 +115,7 @@ public void aStrikeInTheLastFrameGetsATwoRollBonusThatIsCountedOnce() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("rolling a spare with the two roll bonus does not get a bonus roll")
public void rollingASpareWithTheTwoRollBonusDoesNotGetABonusRoll() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3};
@@ -113,6 +125,7 @@ public void rollingASpareWithTheTwoRollBonusDoesNotGetABonusRoll() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("strikes with the two roll bonus do not get bonus rolls")
public void strikesWithTheTwoRollBonusDoNotGetBonusRolls() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10};
@@ -122,6 +135,7 @@ public void strikesWithTheTwoRollBonusDoNotGetBonusRolls() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("last two strikes followed by only last bonus with non strike points")
public void lastTwoStrikesFollowedByOnlyLastBonusWithNonStrikePoints() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 0, 1};
@@ -131,6 +145,7 @@ public void lastTwoStrikesFollowedByOnlyLastBonusWithNonStrikePoints() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a strike with the one roll bonus after a spare in the last frame does not get a bonus")
public void aStrikeWithTheOneRollBonusAfterASpareInTheLastFrameDoesNotGetABonus() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10};
@@ -140,6 +155,7 @@ public void aStrikeWithTheOneRollBonusAfterASpareInTheLastFrameDoesNotGetABonus(
@Disabled("Remove to run test")
@Test
+ @DisplayName("all strikes is a perfect game")
public void allStrikesIsAPerfectGame() {
int[] rolls = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
@@ -149,6 +165,7 @@ public void allStrikesIsAPerfectGame() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("rolls cannot score negative points")
public void rollsCanNotScoreNegativePoints() {
int[] rolls = {-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -159,6 +176,7 @@ public void rollsCanNotScoreNegativePoints() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a roll cannot score more than 10 points")
public void aRollCanNotScoreMoreThan10Points() {
int[] rolls = {11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -169,6 +187,7 @@ public void aRollCanNotScoreMoreThan10Points() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("two rolls in a frame cannot score more than 10 points")
public void twoRollsInAFrameCanNotScoreMoreThan10Points() {
int[] rolls = {5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -179,6 +198,7 @@ public void twoRollsInAFrameCanNotScoreMoreThan10Points() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("bonus roll after a strike in the last frame cannot score more than 10 points")
public void bonusRollAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 0};
@@ -189,6 +209,7 @@ public void bonusRollAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("two bonus rolls after a strike in the last frame cannot score more than 10 points")
public void twoBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 6};
@@ -199,6 +220,7 @@ public void twoBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points()
@Disabled("Remove to run test")
@Test
+ @DisplayName("two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike")
public void twoBonusRollsAfterAStrikeInTheLastFrameCanScoreMoreThan10PointsIfOneIsAStrike() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6};
@@ -209,6 +231,9 @@ public void twoBonusRollsAfterAStrikeInTheLastFrameCanScoreMoreThan10PointsIfOne
@Disabled("Remove to run test")
@Test
+ @DisplayName(
+ "the second bonus rolls after a strike in the last frame cannot be a strike if the first one is not a strike"
+ )
public void theSecondBonusRollsAfterAStrikeInTheLastFrameCanNotBeAStrikeIfTheFirstOneIsNotAStrike() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6, 10};
@@ -219,6 +244,7 @@ public void theSecondBonusRollsAfterAStrikeInTheLastFrameCanNotBeAStrikeIfTheFir
@Disabled("Remove to run test")
@Test
+ @DisplayName("second bonus roll after a strike in the last frame cannot score more than 10 points")
public void secondBonusRollAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 11};
@@ -229,6 +255,7 @@ public void secondBonusRollAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points
@Disabled("Remove to run test")
@Test
+ @DisplayName("an unstarted game cannot be scored")
public void anUnstartedGameCanNotBeScored() {
int[] rolls = new int[0];
@@ -241,6 +268,7 @@ public void anUnstartedGameCanNotBeScored() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("an incomplete game cannot be scored")
public void anIncompleteGameCanNotBeScored() {
int[] rolls = {0, 0};
@@ -253,6 +281,7 @@ public void anIncompleteGameCanNotBeScored() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("cannot roll if game already has ten frames")
public void canNotRollIfGameAlreadyHasTenFrames() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -263,6 +292,7 @@ public void canNotRollIfGameAlreadyHasTenFrames() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("bonus rolls for a strike in the last frame must be rolled before score can be calculated")
public void bonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10};
@@ -275,6 +305,7 @@ public void bonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCalcul
@Disabled("Remove to run test")
@Test
+ @DisplayName("both bonus rolls for a strike in the last frame must be rolled before score can be calculated")
public void bothBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10};
@@ -287,6 +318,7 @@ public void bothBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCa
@Disabled("Remove to run test")
@Test
+ @DisplayName("bonus roll for a spare in the last frame must be rolled before score can be calculated")
public void bonusRollForASpareInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3};
@@ -299,6 +331,7 @@ public void bonusRollForASpareInTheLastFrameMustBeRolledBeforeScoreCanBeCalculat
@Disabled("Remove to run test")
@Test
+ @DisplayName("cannot roll after bonus roll for spare")
public void canNotRollAfterBonusRollForSpare() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 2, 2};
@@ -309,6 +342,7 @@ public void canNotRollAfterBonusRollForSpare() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("cannot roll after bonus rolls for strike")
public void canNotRollAfterBonusRollForStrike() {
int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 3, 2, 2};
diff --git a/exercises/practice/change/.approaches/config.json b/exercises/practice/change/.approaches/config.json
index 00716db81..c24280ab1 100644
--- a/exercises/practice/change/.approaches/config.json
+++ b/exercises/practice/change/.approaches/config.json
@@ -2,20 +2,41 @@
"introduction": {
"authors": [
"jagdish-15"
+ ],
+ "contributors": [
+ "kahgoh"
]
},
"approaches": [
{
"uuid": "d0b615ca-3a02-4d66-ad10-e0c513062189",
- "slug": "dynamic-programming",
- "title": "Dynamic Programming Approach",
- "blurb": "Use dynamic programming to find the most efficient change combination.",
+ "slug": "dynamic-programming-top-down",
+ "title": "Dynamic Programming: Top Down",
+ "blurb": "Break the required amount into smaller amounts and reuse saved results to quickly find the final result.",
"authors": [
"jagdish-15"
],
"contributors": [
"kahgoh"
]
+ },
+ {
+ "uuid": "daf47878-1607-4f22-b2df-1049f3d6802c",
+ "slug": "dynamic-programming-bottom-up",
+ "title": "Dynamic Programming: Bottom Up",
+ "blurb": "Start from the available coins and calculate the amounts that can be made from them.",
+ "authors": [
+ "kahgoh"
+ ]
+ },
+ {
+ "uuid": "06ae63ec-5bf3-41a0-89e3-2772e4cdbf5d",
+ "slug": "recursive",
+ "title": "Recursive",
+ "blurb": "Use recursion to recursively find the most efficient change for a given amount.",
+ "authors": [
+ "kahgoh"
+ ]
}
]
}
diff --git a/exercises/practice/change/.approaches/dynamic-programming-bottom-up/content.md b/exercises/practice/change/.approaches/dynamic-programming-bottom-up/content.md
new file mode 100644
index 000000000..84983df5e
--- /dev/null
+++ b/exercises/practice/change/.approaches/dynamic-programming-bottom-up/content.md
@@ -0,0 +1,84 @@
+# Dynamic Programming - Bottom up
+
+```java
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+class ChangeCalculator {
+
+ private final List currencyCoins;
+
+ ChangeCalculator(List currencyCoins) {
+ this.currencyCoins = List.copyOf(currencyCoins);
+ }
+
+ List computeMostEfficientChange(int grandTotal) {
+ if (grandTotal < 0) {
+ throw new IllegalArgumentException("Negative totals are not allowed.");
+ }
+ if (grandTotal == 0) {
+ return Collections.emptyList();
+ }
+ Set reachableTotals = new HashSet<>();
+ ArrayDeque> queue = new ArrayDeque<>(currencyCoins.stream().map(List::of).toList());
+
+ while (!queue.isEmpty()) {
+ List next = queue.poll();
+ int total = next.stream().mapToInt(Integer::intValue).sum();
+ if (total == grandTotal) {
+ return next;
+ }
+ if (total < grandTotal && reachableTotals.add(total)) {
+ for (Integer coin : currencyCoins) {
+ List toCheck = new ArrayList<>(next);
+ toCheck.add(coin);
+ queue.offer(toCheck);
+ }
+ }
+ }
+
+ throw new IllegalArgumentException("The total " + grandTotal + " cannot be represented in the given currency.");
+ }
+}
+```
+
+This approach starts from the coins and calculates which amounts can be made up by the coins.
+
+The `grandTotal` is first validated to ensure that it is a positive number greater than 0.
+Two data structures are then created:
+
+- a queue to maintain a combination of coins to check
+- a set to keep track of the totals from the combinations that have been seen
+
+The queue is initialized with a number of combinations that consist just each of the coins.
+For example, if the available coins are 5, 10 and 20, then the queue begins with three combinations:
+
+- the first combination has just 5
+- the second has just 10
+- the third has just 20
+
+Thus, the queue contains `[[5], [10], [20]]`.
+
+For each combination in the queue, the loop calculates the sum of the combination.
+If the sum equals the desired total, it has found the combination.
+Otherwise new combinations are added to the queue by adding each of the coins to the end of the combination:
+
+- less than the desired total, and:
+- the total has _not_ yet been "seen" (the Set's [add][set-add] method returns `true` if a new item is being added and `false` if it is already in the Set)
+
+~~~~exercism/note
+If the total has been "seen", there is no need to recheck the amounts because shorter combinations are always checked before longer combinations.
+So, if the total is encountered again, we must have found a shorter combination to reach the same amount earlier.
+~~~~
+
+Continuing with the above example, the first combination contains just `5`.
+When this is processed, the combinations `[5, 5]`, `[5, 10]` and `[5, 20]` would be added to the end of the queue and the queue becomes `[[10], [20],[5 ,5], [5, 10], [5, 20]]` for the next iteration.
+Adding to the end of the queue ensures that the shorter combinations are checked first and allows the combination to simply be returned when the total is reached.
+
+The total can not be reached when there are no combinations in the queue.
+
+[set-add]: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Set.html#add(E)
diff --git a/exercises/practice/change/.approaches/dynamic-programming-bottom-up/snippet.txt b/exercises/practice/change/.approaches/dynamic-programming-bottom-up/snippet.txt
new file mode 100644
index 000000000..354ea1739
--- /dev/null
+++ b/exercises/practice/change/.approaches/dynamic-programming-bottom-up/snippet.txt
@@ -0,0 +1,8 @@
+while (!queue.isEmpty()) {
+ int total = next.stream().mapToInt(Integer::intValue).sum();
+ if (total < grandTotal && reachableTotals.add(total)) {
+ for (Integer coin : currencyCoins) {
+ queue.add(append(next, coin));
+ }
+ }
+}
\ No newline at end of file
diff --git a/exercises/practice/change/.approaches/dynamic-programming/content.md b/exercises/practice/change/.approaches/dynamic-programming-top-down/content.md
similarity index 98%
rename from exercises/practice/change/.approaches/dynamic-programming/content.md
rename to exercises/practice/change/.approaches/dynamic-programming-top-down/content.md
index 640c58a47..06dbf9ba8 100644
--- a/exercises/practice/change/.approaches/dynamic-programming/content.md
+++ b/exercises/practice/change/.approaches/dynamic-programming-top-down/content.md
@@ -1,4 +1,4 @@
-# Dynamic Programming Approach
+# Dynamic Programming - Top Down
```java
import java.util.List;
@@ -12,7 +12,7 @@ class ChangeCalculator {
}
List computeMostEfficientChange(int grandTotal) {
- if (grandTotal < 0)
+ if (grandTotal < 0)
throw new IllegalArgumentException("Negative totals are not allowed.");
List> coinsUsed = new ArrayList<>(grandTotal + 1);
@@ -64,5 +64,5 @@ It minimizes the number of coins needed by breaking down the problem into smalle
## Time and Space Complexity
The time complexity of this approach is **O(n * m)**, where `n` is the `grandTotal` and `m` is the number of available coin denominations. This is because we iterate over all coin denominations for each amount up to `grandTotal`.
-
+
The space complexity is **O(n)** due to the list `coinsUsed`, which stores the most efficient coin combination for each total up to `grandTotal`.
diff --git a/exercises/practice/change/.approaches/dynamic-programming-top-down/snippet.txt b/exercises/practice/change/.approaches/dynamic-programming-top-down/snippet.txt
new file mode 100644
index 000000000..d79e5e5f6
--- /dev/null
+++ b/exercises/practice/change/.approaches/dynamic-programming-top-down/snippet.txt
@@ -0,0 +1,8 @@
+for (int i = 1; i <= grandTotal; i++) {
+ for (int coin: currencyCoins) {
+ List currentCombination = coinsUsed.get(i - coin).add(coin);
+ if (bestCombination == null || currentCombination.size() < bestCombination.size())
+ bestCombination = currentCombination;
+ }
+ coinsUsed.add(bestCombination);
+}
\ No newline at end of file
diff --git a/exercises/practice/change/.approaches/dynamic-programming/snippet.txt b/exercises/practice/change/.approaches/dynamic-programming/snippet.txt
deleted file mode 100644
index 25f90e6f5..000000000
--- a/exercises/practice/change/.approaches/dynamic-programming/snippet.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-class ChangeCalculator {
- private final List currencyCoins;
-
- ChangeCalculator(List currencyCoins) {
- this.currencyCoins = currencyCoins;
- }
- // computeMostEfficientChange method
-}
diff --git a/exercises/practice/change/.approaches/introduction.md b/exercises/practice/change/.approaches/introduction.md
index 672aae038..de92106d8 100644
--- a/exercises/practice/change/.approaches/introduction.md
+++ b/exercises/practice/change/.approaches/introduction.md
@@ -1,14 +1,64 @@
-# Introduction
+# Introduction
-There is an idiomatic approach to solving "Change."
-You can use [dynamic programming][dynamic-programming] to calculate the minimum number of coins required for a given total.
+There are a couple of different ways to solve "Change".
+The [recursive approach][approach-recursive] uses recursion to find most efficient change for remaining amounts assuming a coin is included.
+[Dynamic programming][dynamic-programming] calculates the solution starting from the required total ([the top][approach-dynamic-programming-top-down]) or from the amounts that can be covered by the coins ([the bottom][approach-dynamic-programming-bottom-up]).
## General guidance
The key to solving "Change" is understanding that not all totals can be reached with the available coin denominations.
The solution needs to figure out which totals can be achieved and how to combine the coins optimally.
-## Approach: Dynamic Programming
+## Approach: Recursive
+
+```java
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+class ChangeCalculator {
+
+ private final List currencyCoins;
+
+ ChangeCalculator(List currencyCoins) {
+ this.currencyCoins = List.copyOf(currencyCoins);
+ }
+
+ List computeMostEfficientChange(int grandTotal) {
+ if (grandTotal < 0) {
+ throw new IllegalArgumentException("Negative totals are not allowed.");
+ }
+ if (grandTotal == 0) {
+ return Collections.emptyList();
+ }
+
+ return currencyCoins.stream().map(coin -> {
+ int remaining = grandTotal - coin;
+ if (remaining == 0) {
+ return List.of(coin);
+ }
+
+ try {
+ List result = new ArrayList<>(computeMostEfficientChange(remaining));
+ result.add(coin);
+ result.sort(Integer::compare);
+ return result;
+ } catch (IllegalArgumentException e) {
+ return Collections.emptyList();
+ }
+ })
+ .filter(c -> !c.isEmpty())
+ .min(Comparator.comparingInt(List::size))
+ .orElseThrow(() -> new IllegalArgumentException("The total " + grandTotal + " cannot be represented in the given currency."));
+
+ }
+}
+```
+
+For a detailed look at the code and logic, see the full explanation in the [Recursive Approach][approach-recursive].
+
+## Approach: Dynamic Programming - Top down
```java
import java.util.List;
@@ -22,7 +72,7 @@ class ChangeCalculator {
}
List computeMostEfficientChange(int grandTotal) {
- if (grandTotal < 0)
+ if (grandTotal < 0)
throw new IllegalArgumentException("Negative totals are not allowed.");
List> coinsUsed = new ArrayList<>(grandTotal + 1);
@@ -49,7 +99,64 @@ class ChangeCalculator {
}
```
-For a detailed look at the code and logic, see the full explanation in the [Dynamic Programming Approach][approach-dynamic-programming].
+For a detailed look at the code and logic, see the full explanation in the [Dynamic Programming - Top Down][approach-dynamic-programming-top-down].
+
+## Approach: Dyanmic Programming - Bottom up
+
+```java
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+class ChangeCalculator {
+
+ private final List currencyCoins;
+
+ ChangeCalculator(List currencyCoins) {
+ this.currencyCoins = List.copyOf(currencyCoins);
+ }
+
+ List computeMostEfficientChange(int grandTotal) {
+ if (grandTotal < 0) {
+ throw new IllegalArgumentException("Negative totals are not allowed.");
+ }
+ if (grandTotal == 0) {
+ return Collections.emptyList();
+ }
+ Set reachableTotals = new HashSet<>();
+ ArrayDeque> queue = new ArrayDeque<>(currencyCoins.stream().map(List::of).toList());
+
+ while (!queue.isEmpty()) {
+ List next = queue.poll();
+ int total = next.stream().mapToInt(Integer::intValue).sum();
+ if (total == grandTotal) {
+ return next;
+ }
+ if (total < grandTotal && reachableTotals.add(total)) {
+ for (Integer coin : currencyCoins) {
+ List toCheck = new ArrayList<>(next);
+ toCheck.add(coin);
+ queue.offer(toCheck);
+ }
+ }
+ }
+
+ throw new IllegalArgumentException("The total " + grandTotal + " cannot be represented in the given currency.");
+ }
+}
+```
+
+For a detailed look at the code and logic, see the full explanation in the [Dynamic Programming - Bottom Up][approach-dynamic-programming-bottom-up].
+
+## Which approach to use?
+
+The recursive approach is generally inefficient compared to either dynamic programming approach because the recursion requires recalculating the most efficient change for certain amounts.
+Both dynamic programming approaches avoids this by building on the results computed previously at each step.
-[approach-dynamic-programming]: https://exercism.org/tracks/java/exercises/change/approaches/dynamic-programming
+[approach-recursive]: https://exercism.org/tracks/java/exercises/change/approaches/recursive
+[approach-dynamic-programming-top-down]: https://exercism.org/tracks/java/exercises/change/approaches/dynamic-programming-top-down
+[approach-dynamic-programming-bottom-up]: https://exercism.org/tracks/java/exercises/change/approaches/dynamic-programming-bottom-up
[dynamic-programming]: https://en.wikipedia.org/wiki/Dynamic_programming
diff --git a/exercises/practice/change/.approaches/recursive/content.md b/exercises/practice/change/.approaches/recursive/content.md
new file mode 100644
index 000000000..25ef36dd4
--- /dev/null
+++ b/exercises/practice/change/.approaches/recursive/content.md
@@ -0,0 +1,56 @@
+# Recursive
+
+```java
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+class ChangeCalculator {
+
+ private final List currencyCoins;
+
+ ChangeCalculator(List currencyCoins) {
+ this.currencyCoins = List.copyOf(currencyCoins);
+ }
+
+ List computeMostEfficientChange(int grandTotal) {
+ if (grandTotal < 0) {
+ throw new IllegalArgumentException("Negative totals are not allowed.");
+ }
+ if (grandTotal == 0) {
+ return Collections.emptyList();
+ }
+
+ return currencyCoins.stream().map(coin -> {
+ int remaining = grandTotal - coin;
+ if (remaining == 0) {
+ return List.of(coin);
+ }
+
+ try {
+ List result = new ArrayList<>(computeMostEfficientChange(remaining));
+ result.add(coin);
+ result.sort(Integer::compare);
+ return result;
+ } catch (IllegalArgumentException e) {
+ return Collections.emptyList();
+ }
+ })
+ .filter(c -> !c.isEmpty())
+ .min(Comparator.comparingInt(List::size))
+ .orElseThrow(() -> new IllegalArgumentException("The total " + grandTotal + " cannot be represented in the given currency."));
+
+ }
+}
+```
+
+The recursive approach works by iterating through the available coins and recursively calling itself to find the most efficient change with it.
+It starts by validating the `grandTotal` argument.
+If valid, use a stream to go through the available coins and determines how much change is still required if the coin is included.
+If no more change is required, the most efficient change consists simply of the coin on its own.
+Otherwise it will recursively call itself to find the most efficient change for the remaining amount.
+The recursive call is done in a `try-catch` block because the method throws an `IllegalArgumentionException` if the change can not be made.
+An empty list is used to indicate when the change can not be made in the stream.
+The stream filters out the empty list in the next step before finding the smallest list.
+If the stream is empty, an `IllegalArgumentException` is thrown to indicate the change could not be made.
diff --git a/exercises/practice/change/.approaches/recursive/snippet.txt b/exercises/practice/change/.approaches/recursive/snippet.txt
new file mode 100644
index 000000000..64c6f9df8
--- /dev/null
+++ b/exercises/practice/change/.approaches/recursive/snippet.txt
@@ -0,0 +1,7 @@
+List computeMostEfficientChange(int grandTotal) {
+ if (remaining == 0)
+ return List.of(coin);
+
+ return currencyCoins.stream().map(coin ->
+ new ArrayList<>(computeMostEfficientChange(remaining)).add(coin));
+}
\ No newline at end of file
diff --git a/exercises/practice/change/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/change/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/change/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/change/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/change/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/change/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/change/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/change/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/change/gradlew b/exercises/practice/change/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/change/gradlew
+++ b/exercises/practice/change/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/change/gradlew.bat b/exercises/practice/change/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/change/gradlew.bat
+++ b/exercises/practice/change/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/change/src/test/java/ChangeCalculatorTest.java b/exercises/practice/change/src/test/java/ChangeCalculatorTest.java
index e685c28d0..b88c316d3 100644
--- a/exercises/practice/change/src/test/java/ChangeCalculatorTest.java
+++ b/exercises/practice/change/src/test/java/ChangeCalculatorTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static java.util.Arrays.asList;
@@ -8,7 +9,8 @@
public class ChangeCalculatorTest {
@Test
- public void testChangeFor1Cent() {
+ @DisplayName("change for 1 cent")
+ public void testChangeForOneCent() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(1, 5, 10, 25));
assertThat(changeCalculator.computeMostEfficientChange(1))
@@ -17,6 +19,7 @@ public void testChangeFor1Cent() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("single coin change")
public void testChangeThatCanBeGivenInASingleCoin() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(1, 5, 10, 25, 100));
@@ -26,6 +29,7 @@ public void testChangeThatCanBeGivenInASingleCoin() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("multiple coin change")
public void testChangeThatMustBeGivenInMultipleCoins() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(1, 5, 10, 25, 100));
@@ -35,6 +39,7 @@ public void testChangeThatMustBeGivenInMultipleCoins() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("change with Lilliputian Coins")
public void testLilliputianCurrency() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(1, 4, 15, 20, 50));
@@ -44,6 +49,7 @@ public void testLilliputianCurrency() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("change with Lower Elbonia Coins")
public void testLowerElbonianCurrency() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(1, 5, 10, 21, 25));
@@ -53,6 +59,7 @@ public void testLowerElbonianCurrency() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("large target values")
public void testLargeAmountOfChange() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(1, 2, 5, 10, 20, 50, 100));
@@ -62,6 +69,7 @@ public void testLargeAmountOfChange() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("possible change without unit coins available")
public void testPossibleChangeWithoutUnitCoinAvailable() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(2, 5, 10, 20, 50));
@@ -71,6 +79,7 @@ public void testPossibleChangeWithoutUnitCoinAvailable() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("another possible change without unit coins available")
public void testAnotherPossibleChangeWithoutUnitCoinAvailable() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(4, 5));
@@ -80,6 +89,7 @@ public void testAnotherPossibleChangeWithoutUnitCoinAvailable() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a greedy approach is not optimal")
public void testAGreedyApproachIsNotOptimal() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(1, 10, 11));
@@ -89,6 +99,7 @@ public void testAGreedyApproachIsNotOptimal() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("no coins make 0 change")
public void testZeroChange() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(1, 5, 10, 21, 25));
@@ -98,6 +109,7 @@ public void testZeroChange() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("error testing for change smaller than the smallest of coins")
public void testChangeLessThanSmallestCoinInCurrencyCannotBeRepresented() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(5, 10));
@@ -108,6 +120,7 @@ public void testChangeLessThanSmallestCoinInCurrencyCannotBeRepresented() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("error if no combination can add up to target")
public void testChangeLargerThanAllCoinsInCurrencyThatCannotBeRepresented() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(5, 10));
@@ -118,6 +131,7 @@ public void testChangeLargerThanAllCoinsInCurrencyThatCannotBeRepresented() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("cannot find negative change values")
public void testNegativeChangeIsRejected() {
ChangeCalculator changeCalculator = new ChangeCalculator(asList(1, 2, 5));
diff --git a/exercises/practice/circular-buffer/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/circular-buffer/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/circular-buffer/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/circular-buffer/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/circular-buffer/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/circular-buffer/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/circular-buffer/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/circular-buffer/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/circular-buffer/gradlew b/exercises/practice/circular-buffer/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/circular-buffer/gradlew
+++ b/exercises/practice/circular-buffer/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/circular-buffer/gradlew.bat b/exercises/practice/circular-buffer/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/circular-buffer/gradlew.bat
+++ b/exercises/practice/circular-buffer/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/circular-buffer/src/test/java/CircularBufferTest.java b/exercises/practice/circular-buffer/src/test/java/CircularBufferTest.java
index 1596b3535..6ecbc1930 100644
--- a/exercises/practice/circular-buffer/src/test/java/CircularBufferTest.java
+++ b/exercises/practice/circular-buffer/src/test/java/CircularBufferTest.java
@@ -2,11 +2,13 @@
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 CircularBufferTest {
@Test
+ @DisplayName("reading empty buffer should fail")
public void readingFromEmptyBufferShouldThrowException() {
CircularBuffer buffer = new CircularBuffer<>(1);
@@ -17,6 +19,7 @@ public void readingFromEmptyBufferShouldThrowException() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can read an item just written")
public void canReadItemJustWritten() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(1);
@@ -26,6 +29,7 @@ public void canReadItemJustWritten() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("each item may only be read once")
public void canReadItemOnlyOnce() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(1);
@@ -39,6 +43,7 @@ public void canReadItemOnlyOnce() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("items are read in the order they are written")
public void readsItemsInOrderWritten() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(2);
@@ -50,6 +55,7 @@ public void readsItemsInOrderWritten() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("full buffer can't be written to")
public void fullBufferCantBeWrittenTo() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(1);
@@ -62,6 +68,7 @@ public void fullBufferCantBeWrittenTo() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("a read frees up capacity for another write")
public void readFreesUpSpaceForWrite() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(1);
@@ -73,6 +80,7 @@ public void readFreesUpSpaceForWrite() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("read position is maintained even across multiple writes")
public void maintainsReadPositionAcrossWrites() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(3);
@@ -86,6 +94,7 @@ public void maintainsReadPositionAcrossWrites() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("items cleared out of buffer can't be read")
public void cantReadClearedItems() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(1);
@@ -99,6 +108,7 @@ public void cantReadClearedItems() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clear frees up capacity for another write")
public void clearFreesUpCapacity() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(1);
@@ -110,6 +120,7 @@ public void clearFreesUpCapacity() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clear does nothing on empty buffer")
public void clearDoesNothingOnEmptyBuffer() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(1);
@@ -120,6 +131,7 @@ public void clearDoesNothingOnEmptyBuffer() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("overwrite acts like write on non-full buffer")
public void overwriteActsLikeWriteOnNonFullBuffer() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(2);
@@ -131,6 +143,7 @@ public void overwriteActsLikeWriteOnNonFullBuffer() throws BufferIOException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("overwrite replaces the oldest item on full buffer")
public void overwriteRemovesOldestElementOnFullBuffer() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(2);
@@ -143,6 +156,7 @@ public void overwriteRemovesOldestElementOnFullBuffer() throws BufferIOException
@Disabled("Remove to run test")
@Test
+ @DisplayName("overwrite replaces the oldest item remaining in buffer following a read")
public void overwriteDoesntRemoveAnAlreadyReadElement() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(3);
@@ -159,6 +173,7 @@ public void overwriteDoesntRemoveAnAlreadyReadElement() throws BufferIOException
@Disabled("Remove to run test")
@Test
+ @DisplayName("initial clear does not affect wrapping around")
public void initialClearDoesNotAffectWrappingAround() throws BufferIOException {
CircularBuffer buffer = new CircularBuffer<>(2);
diff --git a/exercises/practice/clock/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/clock/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/clock/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/clock/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/clock/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/clock/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/clock/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/clock/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/clock/gradlew b/exercises/practice/clock/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/clock/gradlew
+++ b/exercises/practice/clock/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/clock/gradlew.bat b/exercises/practice/clock/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/clock/gradlew.bat
+++ b/exercises/practice/clock/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/clock/src/test/java/ClockAddTest.java b/exercises/practice/clock/src/test/java/ClockAddTest.java
index 34c22e06b..1a82b687e 100644
--- a/exercises/practice/clock/src/test/java/ClockAddTest.java
+++ b/exercises/practice/clock/src/test/java/ClockAddTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -7,6 +8,7 @@ public class ClockAddTest {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add minutes")
public void addMinutes() {
Clock clock = new Clock(10, 0);
clock.add(3);
@@ -16,6 +18,7 @@ public void addMinutes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add no minutes")
public void addNoMinutes() {
Clock clock = new Clock(6, 41);
clock.add(0);
@@ -25,6 +28,7 @@ public void addNoMinutes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add to next hour")
public void addToNextHour() {
Clock clock = new Clock(0, 45);
clock.add(40);
@@ -34,6 +38,7 @@ public void addToNextHour() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add more than one hour")
public void addMoreThanOneHour() {
Clock clock = new Clock(10, 0);
clock.add(61);
@@ -43,6 +48,7 @@ public void addMoreThanOneHour() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add more than two hours with carry")
public void addMoreThanTwoHoursWithCarry() {
Clock clock = new Clock(0, 45);
clock.add(160);
@@ -52,6 +58,7 @@ public void addMoreThanTwoHoursWithCarry() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add across midnight")
public void addAcrossMidnight() {
Clock clock = new Clock(23, 59);
clock.add(2);
@@ -61,6 +68,7 @@ public void addAcrossMidnight() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add more than one day (1500 min = 25 hrs)")
public void addMoreThanOneDay() {
Clock clock = new Clock(5, 32);
clock.add(1500);
@@ -70,6 +78,7 @@ public void addMoreThanOneDay() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add more than two days")
public void addMoreThanTwoDays() {
Clock clock = new Clock(1, 1);
clock.add(3500);
@@ -79,6 +88,7 @@ public void addMoreThanTwoDays() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("subtract minutes")
public void subtractMinutes() {
Clock clock = new Clock(10, 3);
clock.add(-3);
@@ -88,6 +98,7 @@ public void subtractMinutes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("subtract to previous hour")
public void subtractToPreviousHour() {
Clock clock = new Clock(10, 3);
clock.add(-30);
@@ -97,6 +108,7 @@ public void subtractToPreviousHour() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("subtract more than an hour")
public void subtractMoreThanAnHour() {
Clock clock = new Clock(10, 3);
clock.add(-70);
@@ -106,6 +118,7 @@ public void subtractMoreThanAnHour() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("subtract across midnight")
public void subtractAcrossMidnight() {
Clock clock = new Clock(0, 3);
clock.add(-4);
@@ -115,6 +128,7 @@ public void subtractAcrossMidnight() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("subtract more than two hours")
public void subtractMoreThanTwoHours() {
Clock clock = new Clock(0, 0);
clock.add(-160);
@@ -124,6 +138,7 @@ public void subtractMoreThanTwoHours() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("subtract more than two hours with borrow")
public void subtractMoreThanTwoHoursWithBorrow() {
Clock clock = new Clock(6, 15);
clock.add(-160);
@@ -133,6 +148,7 @@ public void subtractMoreThanTwoHoursWithBorrow() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("subtract more than one day (1500 min = 25 hrs)")
public void subtractMoreThanOneDay() {
Clock clock = new Clock(5, 32);
clock.add(-1500);
@@ -142,6 +158,7 @@ public void subtractMoreThanOneDay() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("subtract more than two days")
public void subtractMoreThanTwoDays() {
Clock clock = new Clock(2, 20);
clock.add(-3000);
diff --git a/exercises/practice/clock/src/test/java/ClockCreationTest.java b/exercises/practice/clock/src/test/java/ClockCreationTest.java
index 84f68d60d..674d1fee7 100644
--- a/exercises/practice/clock/src/test/java/ClockCreationTest.java
+++ b/exercises/practice/clock/src/test/java/ClockCreationTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -6,120 +7,140 @@
public class ClockCreationTest {
@Test
+ @DisplayName("on the hour")
public void canPrintTimeOnTheHour() {
assertThat(new Clock(8, 0).toString()).isEqualTo("08:00");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("past the hour")
public void canPrintTimeWithMinutes() {
assertThat(new Clock(11, 9).toString()).isEqualTo("11:09");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("midnight is zero hours")
public void midnightPrintsAsZero() {
assertThat(new Clock(24, 0).toString()).isEqualTo("00:00");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("hour rolls over")
public void hourRollsOver() {
assertThat(new Clock(25, 0).toString()).isEqualTo("01:00");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("hour rolls over continuously")
public void hourRollsOverContinuously() {
assertThat(new Clock(100, 0).toString()).isEqualTo("04:00");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("sixty minutes is next hour")
public void sixtyMinutesIsNextHour() {
assertThat(new Clock(1, 60).toString()).isEqualTo("02:00");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("minutes roll over")
public void minutesRollOver() {
assertThat(new Clock(0, 160).toString()).isEqualTo("02:40");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("minutes roll over continuously")
public void minutesRollOverContinuously() {
assertThat(new Clock(0, 1723).toString()).isEqualTo("04:43");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("hour and minutes roll over")
public void hourAndMinutesRollOver() {
assertThat(new Clock(25, 160).toString()).isEqualTo("03:40");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("hour and minutes roll over continuously")
public void hourAndMinutesRollOverContinuously() {
assertThat(new Clock(201, 3001).toString()).isEqualTo("11:01");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("hour and minutes roll over to exactly midnight")
public void hourAndMinutesRollOverToExactlyMidnight() {
assertThat(new Clock(72, 8640).toString()).isEqualTo("00:00");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative hour")
public void negativeHour() {
assertThat(new Clock(-1, 15).toString()).isEqualTo("23:15");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative hour rolls over")
public void negativeHourRollsOver() {
assertThat(new Clock(-25, 0).toString()).isEqualTo("23:00");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative hour rolls over continuously")
public void negativeHourRollsOverContinuously() {
assertThat(new Clock(-91, 0).toString()).isEqualTo("05:00");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative minutes")
public void negativeMinutes() {
assertThat(new Clock(1, -40).toString()).isEqualTo("00:20");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative minutes roll over")
public void negativeMinutesRollOver() {
assertThat(new Clock(1, -160).toString()).isEqualTo("22:20");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative minutes roll over continuously")
public void negativeMinutesRollOverContinuously() {
assertThat(new Clock(1, -4820).toString()).isEqualTo("16:40");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative sixty minutes is previous hour")
public void negativeSixtyMinutesIsPreviousHour() {
assertThat(new Clock(2, -60).toString()).isEqualTo("01:00");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative hour and minutes both roll over")
public void negativeHourAndMinutesBothRollOver() {
assertThat(new Clock(-25, -160).toString()).isEqualTo("20:20");
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative hour and minutes both roll over continuously")
public void negativeHourAndMinutesBothRollOverContinuously() {
assertThat(new Clock(-121, -5810).toString()).isEqualTo("22:10");
}
diff --git a/exercises/practice/clock/src/test/java/ClockEqualTest.java b/exercises/practice/clock/src/test/java/ClockEqualTest.java
index 0ec041f71..d73687773 100644
--- a/exercises/practice/clock/src/test/java/ClockEqualTest.java
+++ b/exercises/practice/clock/src/test/java/ClockEqualTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -7,6 +8,7 @@ public class ClockEqualTest {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with same time")
public void clocksWithSameTimeAreEqual() {
assertThat(new Clock(15, 37))
.isEqualTo(new Clock(15, 37));
@@ -14,6 +16,7 @@ public void clocksWithSameTimeAreEqual() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks a minute apart")
public void clocksAMinuteApartAreNotEqual() {
assertThat(new Clock(15, 36))
.isNotEqualTo(new Clock(15, 37));
@@ -21,6 +24,7 @@ public void clocksAMinuteApartAreNotEqual() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks an hour apart")
public void clocksAnHourApartAreNotEqual() {
assertThat(new Clock(14, 37))
.isNotEqualTo(new Clock(15, 37));
@@ -28,6 +32,7 @@ public void clocksAnHourApartAreNotEqual() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with hour overflow")
public void clocksWithHourOverflow() {
assertThat(new Clock(34, 37))
.isEqualTo(new Clock(10, 37));
@@ -35,6 +40,7 @@ public void clocksWithHourOverflow() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with hour overflow by several days")
public void clocksWithHourOverflowBySeveralDays() {
assertThat(new Clock(99, 11))
.isEqualTo(new Clock(3, 11));
@@ -42,6 +48,7 @@ public void clocksWithHourOverflowBySeveralDays() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with negative hour")
public void clocksWithNegateHour() {
assertThat(new Clock(-2, 40))
.isEqualTo(new Clock(22, 40));
@@ -49,6 +56,7 @@ public void clocksWithNegateHour() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with negative hour that wraps")
public void clocksWithNegativeHourThatWraps() {
assertThat(new Clock(-31, 3))
.isEqualTo(new Clock(17, 3));
@@ -56,6 +64,7 @@ public void clocksWithNegativeHourThatWraps() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with negative hour that wraps multiple times")
public void clocksWithNegativeHourThatWrapsMultipleTimes() {
assertThat(new Clock(-83, 49))
.isEqualTo(new Clock(13, 49));
@@ -63,6 +72,7 @@ public void clocksWithNegativeHourThatWrapsMultipleTimes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with minute overflow")
public void clocksWithMinuteOverflow() {
assertThat(new Clock(0, 1441))
.isEqualTo(new Clock(0, 1));
@@ -70,6 +80,7 @@ public void clocksWithMinuteOverflow() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with minute overflow by several days")
public void clocksWithMinuteOverflowBySeveralDays() {
assertThat(new Clock(2, 4322))
.isEqualTo(new Clock(2, 2));
@@ -77,6 +88,7 @@ public void clocksWithMinuteOverflowBySeveralDays() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with negative minute")
public void clocksWithNegativeMinutes() {
assertThat(new Clock(3, -20))
.isEqualTo(new Clock(2, 40));
@@ -84,6 +96,7 @@ public void clocksWithNegativeMinutes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with negative minute that wraps")
public void clocksWithNegativeMinutesThatWraps() {
assertThat(new Clock(5, -1490))
.isEqualTo(new Clock(4, 10));
@@ -91,6 +104,7 @@ public void clocksWithNegativeMinutesThatWraps() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with negative minute that wraps multiple times")
public void clocksWithNegativeMinutesThatWrapsMultipleTimes() {
assertThat(new Clock(6, -4305))
.isEqualTo(new Clock(6, 15));
@@ -98,6 +112,7 @@ public void clocksWithNegativeMinutesThatWrapsMultipleTimes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with negative hours and minutes")
public void clocksWithNegativeHoursAndMinutes() {
assertThat(new Clock(-12, -268))
.isEqualTo(new Clock(7, 32));
@@ -105,6 +120,7 @@ public void clocksWithNegativeHoursAndMinutes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("clocks with negative hours and minutes that wrap")
public void clocksWithNegativeHoursAndMinutesThatWrap() {
assertThat(new Clock(-54, -11513))
.isEqualTo(new Clock(18, 7));
@@ -112,6 +128,7 @@ public void clocksWithNegativeHoursAndMinutesThatWrap() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("full clock and zeroed clock")
public void clocksWithFullClockAndZeroedClockAreEqual() {
assertThat(new Clock(24, 0))
.isEqualTo(new Clock(0, 0));
diff --git a/exercises/practice/collatz-conjecture/.approaches/introduction.md b/exercises/practice/collatz-conjecture/.approaches/introduction.md
index 9965c8ffc..6717d2046 100644
--- a/exercises/practice/collatz-conjecture/.approaches/introduction.md
+++ b/exercises/practice/collatz-conjecture/.approaches/introduction.md
@@ -1,6 +1,6 @@
# Introduction
-There are at east a couple of ways to solve Collatz Conjecture.
+There are at least a couple of ways to solve Collatz Conjecture.
One approach is to use a [`while`][while-loop] loop to iterate to the answer.
Another approach is to use `IntStream.iterate()` to iterate to the answer.
diff --git a/exercises/practice/collatz-conjecture/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/collatz-conjecture/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/collatz-conjecture/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/collatz-conjecture/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/collatz-conjecture/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/collatz-conjecture/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/collatz-conjecture/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/collatz-conjecture/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/collatz-conjecture/gradlew b/exercises/practice/collatz-conjecture/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/collatz-conjecture/gradlew
+++ b/exercises/practice/collatz-conjecture/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/collatz-conjecture/gradlew.bat b/exercises/practice/collatz-conjecture/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/collatz-conjecture/gradlew.bat
+++ b/exercises/practice/collatz-conjecture/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/collatz-conjecture/src/test/java/CollatzCalculatorTest.java b/exercises/practice/collatz-conjecture/src/test/java/CollatzCalculatorTest.java
index 708d608dc..c095ffdf6 100644
--- a/exercises/practice/collatz-conjecture/src/test/java/CollatzCalculatorTest.java
+++ b/exercises/practice/collatz-conjecture/src/test/java/CollatzCalculatorTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -9,30 +10,35 @@ public class CollatzCalculatorTest {
private CollatzCalculator collatzCalculator = new CollatzCalculator();
@Test
+ @DisplayName("zero steps for one")
public void testZeroStepsRequiredWhenStartingFrom1() {
assertThat(collatzCalculator.computeStepCount(1)).isEqualTo(0);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("divide if even")
public void testCorrectNumberOfStepsWhenAllStepsAreDivisions() {
assertThat(collatzCalculator.computeStepCount(16)).isEqualTo(4);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("even and odd steps")
public void testCorrectNumberOfStepsWhenBothStepTypesAreNeeded() {
assertThat(collatzCalculator.computeStepCount(12)).isEqualTo(9);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("large number of even and odd steps")
public void testAVeryLargeInput() {
assertThat(collatzCalculator.computeStepCount(1000000)).isEqualTo(152);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("zero is an error")
public void testZeroIsConsideredInvalidInput() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> collatzCalculator.computeStepCount(0))
@@ -41,6 +47,7 @@ public void testZeroIsConsideredInvalidInput() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative value is an error")
public void testNegativeIntegerIsConsideredInvalidInput() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> collatzCalculator.computeStepCount(-15))
diff --git a/exercises/practice/complex-numbers/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/complex-numbers/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/complex-numbers/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/complex-numbers/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/complex-numbers/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/complex-numbers/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/complex-numbers/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/complex-numbers/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/complex-numbers/gradlew b/exercises/practice/complex-numbers/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/complex-numbers/gradlew
+++ b/exercises/practice/complex-numbers/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/complex-numbers/gradlew.bat b/exercises/practice/complex-numbers/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/complex-numbers/gradlew.bat
+++ b/exercises/practice/complex-numbers/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/complex-numbers/src/test/java/ComplexNumberTest.java b/exercises/practice/complex-numbers/src/test/java/ComplexNumberTest.java
index 1d479ea68..d9edc378a 100644
--- a/exercises/practice/complex-numbers/src/test/java/ComplexNumberTest.java
+++ b/exercises/practice/complex-numbers/src/test/java/ComplexNumberTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -24,6 +25,7 @@ private void assertComplexNumbersEqual(ComplexNumber c1, ComplexNumber c2) {
// Tests
@Test
+ @DisplayName("Real part of a purely real number")
public void testRealPartOfPurelyRealNumber() {
double expected = 1.0;
double actual = new ComplexNumber(1.0, 0).getReal();
@@ -32,6 +34,7 @@ public void testRealPartOfPurelyRealNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Real part of a purely imaginary number")
public void testRealPartOfPurelyImaginaryNumber() {
double expected = 0.0;
double actual = new ComplexNumber(0, 1.0).getReal();
@@ -40,6 +43,7 @@ public void testRealPartOfPurelyImaginaryNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Real part of a number with real and imaginary part")
public void testRealPartOfNumberWithRealAndImaginaryParts() {
double expected = 1.0;
double actual = new ComplexNumber(1.0, 2.0).getReal();
@@ -48,6 +52,7 @@ public void testRealPartOfNumberWithRealAndImaginaryParts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Imaginary part of a purely real number")
public void testImaginaryPartOfPurelyRealNumber() {
double expected = 0.0;
double actual = new ComplexNumber(1.0, 0).getImaginary();
@@ -56,6 +61,7 @@ public void testImaginaryPartOfPurelyRealNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Imaginary part of a purely imaginary number")
public void testImaginaryPartOfPurelyImaginaryNumber() {
double expected = 1.0;
double actual = new ComplexNumber(0, 1.0).getImaginary();
@@ -64,6 +70,7 @@ public void testImaginaryPartOfPurelyImaginaryNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Imaginary part of a number with real and imaginary part")
public void testImaginaryPartOfNumberWithRealAndImaginaryParts() {
double expected = 2.0;
double actual = new ComplexNumber(1.0, 2.0).getImaginary();
@@ -72,6 +79,7 @@ public void testImaginaryPartOfNumberWithRealAndImaginaryParts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Imaginary unit")
public void testImaginaryUnitExhibitsDefiningProperty() {
ComplexNumber expected = new ComplexNumber(-1.0, 0);
ComplexNumber actual = new ComplexNumber(0, 1.0).multiply(new ComplexNumber(0, 1.0));
@@ -80,6 +88,7 @@ public void testImaginaryUnitExhibitsDefiningProperty() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Add purely real numbers")
public void testAdditionWithPurelyRealNumbers() {
ComplexNumber expected = new ComplexNumber(3.0, 0);
ComplexNumber actual = new ComplexNumber(1.0, 0).add(new ComplexNumber(2.0, 0));
@@ -88,6 +97,7 @@ public void testAdditionWithPurelyRealNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Add purely imaginary numbers")
public void testAdditionWithPurelyImaginaryNumbers() {
ComplexNumber expected = new ComplexNumber(0, 3.0);
ComplexNumber actual = new ComplexNumber(0, 1.0).add(new ComplexNumber(0, 2.0));
@@ -96,6 +106,7 @@ public void testAdditionWithPurelyImaginaryNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Add numbers with real and imaginary part")
public void testAdditionWithRealAndImaginaryParts() {
ComplexNumber expected = new ComplexNumber(4.0, 6.0);
ComplexNumber actual = new ComplexNumber(1.0, 2.0).add(new ComplexNumber(3.0, 4.0));
@@ -104,6 +115,7 @@ public void testAdditionWithRealAndImaginaryParts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Subtract purely real numbers")
public void testSubtractionWithPurelyRealNumbers() {
ComplexNumber expected = new ComplexNumber(-1.0, 0.0);
ComplexNumber actual = new ComplexNumber(1.0, 0.0).subtract(new ComplexNumber(2.0, 0.0));
@@ -112,6 +124,7 @@ public void testSubtractionWithPurelyRealNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Subtract purely imaginary numbers")
public void testSubtractionWithPurelyImaginaryNumbers() {
ComplexNumber expected = new ComplexNumber(0, -1.0);
ComplexNumber actual = new ComplexNumber(0, 1.0).subtract(new ComplexNumber(0, 2.0));
@@ -120,6 +133,7 @@ public void testSubtractionWithPurelyImaginaryNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Subtract numbers with real and imaginary part")
public void testSubtractionWithRealAndImaginaryParts() {
ComplexNumber expected = new ComplexNumber(-2.0, -2.0);
ComplexNumber actual = new ComplexNumber(1.0, 2.0).subtract(new ComplexNumber(3.0, 4.0));
@@ -128,6 +142,7 @@ public void testSubtractionWithRealAndImaginaryParts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiply purely real numbers")
public void testMultiplicationWithPurelyRealNumbers() {
ComplexNumber expected = new ComplexNumber(2.0, 0);
ComplexNumber actual = new ComplexNumber(1.0, 0).multiply(new ComplexNumber(2.0, 0));
@@ -136,6 +151,7 @@ public void testMultiplicationWithPurelyRealNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiply purely imaginary numbers")
public void testMultiplicationWithPurelyImaginaryNumbers() {
ComplexNumber expected = new ComplexNumber(-2.0, 0);
ComplexNumber actual = new ComplexNumber(0, 1.0).multiply(new ComplexNumber(0, 2.0));
@@ -144,6 +160,7 @@ public void testMultiplicationWithPurelyImaginaryNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiply numbers with real and imaginary part")
public void testMultiplicationWithRealAndImaginaryParts() {
ComplexNumber expected = new ComplexNumber(-5.0, 10.0);
ComplexNumber actual = new ComplexNumber(1.0, 2.0).multiply(new ComplexNumber(3.0, 4.0));
@@ -152,6 +169,7 @@ public void testMultiplicationWithRealAndImaginaryParts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Divide purely real numbers")
public void testDivisionWithPurelyRealNumbers() {
ComplexNumber expected = new ComplexNumber(0.5, 0);
ComplexNumber actual = new ComplexNumber(1.0, 0).divide(new ComplexNumber(2.0, 0));
@@ -160,6 +178,7 @@ public void testDivisionWithPurelyRealNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Divide purely imaginary numbers")
public void testDivisionWithPurelyImaginaryNumbers() {
ComplexNumber expected = new ComplexNumber(0.5, 0);
ComplexNumber actual = new ComplexNumber(0, 1.0).divide(new ComplexNumber(0, 2.0));
@@ -168,6 +187,7 @@ public void testDivisionWithPurelyImaginaryNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Divide numbers with real and imaginary part")
public void testDivisionWithRealAndImaginaryParts() {
ComplexNumber expected = new ComplexNumber(0.44, 0.08);
ComplexNumber actual = new ComplexNumber(1.0, 2.0).divide(new ComplexNumber(3.0, 4.0));
@@ -176,6 +196,7 @@ public void testDivisionWithRealAndImaginaryParts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Absolute value of a positive purely real number")
public void testAbsoluteValueOfPositivePurelyRealNumber() {
double expected = 5.0;
double actual = new ComplexNumber(5.0, 0).abs();
@@ -184,6 +205,7 @@ public void testAbsoluteValueOfPositivePurelyRealNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Absolute value of a negative purely real number")
public void testAbsoluteValueOfNegativePurelyRealNumber() {
double expected = 5.0;
double actual = new ComplexNumber(-5.0, 0).abs();
@@ -192,6 +214,7 @@ public void testAbsoluteValueOfNegativePurelyRealNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Absolute value of a purely imaginary number with positive imaginary part")
public void testAbsoluteValueOfPurelyImaginaryNumberWithPositiveImaginaryPart() {
double expected = 5.0;
double actual = new ComplexNumber(0, 5.0).abs();
@@ -200,6 +223,7 @@ public void testAbsoluteValueOfPurelyImaginaryNumberWithPositiveImaginaryPart()
@Disabled("Remove to run test")
@Test
+ @DisplayName("Absolute value of a purely imaginary number with negative imaginary part")
public void testAbsoluteValueOfPurelyImaginaryNumberWithNegativeImaginaryPart() {
double expected = 5.0;
double actual = new ComplexNumber(0, -5.0).abs();
@@ -208,6 +232,7 @@ public void testAbsoluteValueOfPurelyImaginaryNumberWithNegativeImaginaryPart()
@Disabled("Remove to run test")
@Test
+ @DisplayName("Absolute value of a number with real and imaginary part")
public void testAbsoluteValueOfNumberWithRealAndImaginaryParts() {
double expected = 5.0;
double actual = new ComplexNumber(3.0, 4.0).abs();
@@ -216,6 +241,7 @@ public void testAbsoluteValueOfNumberWithRealAndImaginaryParts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Conjugate a purely real number")
public void testConjugationOfPurelyRealNumber() {
ComplexNumber expected = new ComplexNumber(5.0, 0);
ComplexNumber actual = new ComplexNumber(5.0, 0).conjugate();
@@ -224,6 +250,7 @@ public void testConjugationOfPurelyRealNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Conjugate a purely imaginary number")
public void testConjugationOfPurelyImaginaryNumber() {
ComplexNumber expected = new ComplexNumber(0, -5.0);
ComplexNumber actual = new ComplexNumber(0, 5.0).conjugate();
@@ -232,6 +259,7 @@ public void testConjugationOfPurelyImaginaryNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Conjugate a number with real and imaginary part")
public void testConjugationOfNumberWithRealAndImaginaryParts() {
ComplexNumber expected = new ComplexNumber(1.0, -1.0);
ComplexNumber actual = new ComplexNumber(1.0, 1.0).conjugate();
@@ -240,6 +268,7 @@ public void testConjugationOfNumberWithRealAndImaginaryParts() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Euler's identity/formula")
public void testExponentialOfPurelyImaginaryNumber() {
ComplexNumber expected = new ComplexNumber(-1.0, 0);
ComplexNumber actual = new ComplexNumber(0, Math.PI).exponentialOf();
@@ -248,6 +277,7 @@ public void testExponentialOfPurelyImaginaryNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Exponential of 0")
public void testExponentialOfZero() {
ComplexNumber expected = new ComplexNumber(1.0, 0);
ComplexNumber actual = new ComplexNumber(0, 0).exponentialOf();
@@ -256,6 +286,7 @@ public void testExponentialOfZero() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Exponential of a purely real number")
public void testExponentialOfPurelyRealNumber() {
ComplexNumber expected = new ComplexNumber(Math.E, 0);
ComplexNumber actual = new ComplexNumber(1.0, 0).exponentialOf();
@@ -264,6 +295,7 @@ public void testExponentialOfPurelyRealNumber() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Exponential resulting in a number with real and imaginary part")
public void testExponentialOfNumberWithRealAndImaginaryParts() {
ComplexNumber expected = new ComplexNumber(1, 1);
ComplexNumber actual = new ComplexNumber(Math.log(2.0) / 2, Math.PI / 4).exponentialOf();
diff --git a/exercises/practice/connect/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/connect/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/connect/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/connect/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/connect/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/connect/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/connect/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/connect/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/connect/gradlew b/exercises/practice/connect/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/connect/gradlew
+++ b/exercises/practice/connect/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/connect/gradlew.bat b/exercises/practice/connect/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/connect/gradlew.bat
+++ b/exercises/practice/connect/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/connect/src/test/java/ConnectTest.java b/exercises/practice/connect/src/test/java/ConnectTest.java
index e6bfa17c8..0bc3a12a2 100644
--- a/exercises/practice/connect/src/test/java/ConnectTest.java
+++ b/exercises/practice/connect/src/test/java/ConnectTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -6,6 +7,7 @@
public class ConnectTest {
@Test
+ @DisplayName("an empty board has no winner")
public void anEmptyBoardHasNoWinner() {
//GIVEN
@@ -27,6 +29,7 @@ public void anEmptyBoardHasNoWinner() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("X can win on a 1x1 board")
public void xCanWinOnA1x1Board() {
//GIVEN
@@ -45,6 +48,7 @@ public void xCanWinOnA1x1Board() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("O can win on a 1x1 board")
public void oCanWinOnA1x1Board() {
//GIVEN
@@ -63,6 +67,7 @@ public void oCanWinOnA1x1Board() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("only edges does not make a winner")
public void onlyEdgesDoesNotMakeAWinner() {
//GIVEN
@@ -84,6 +89,7 @@ public void onlyEdgesDoesNotMakeAWinner() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("illegal diagonal does not make a winner")
public void illegalDiagonalDoesNotMakeAWinner() {
//GIVEN
@@ -106,6 +112,7 @@ public void illegalDiagonalDoesNotMakeAWinner() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("nobody wins crossing adjacent angles")
public void nobodyWinsCrossingAdjacentAngles() {
//GIVEN
@@ -128,6 +135,7 @@ public void nobodyWinsCrossingAdjacentAngles() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("X wins crossing from left to right")
public void xWinsCrossingFromLeftToRight() {
//GIVEN
@@ -150,6 +158,7 @@ public void xWinsCrossingFromLeftToRight() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("O wins crossing from top to bottom")
public void oWinsCrossingFromTopToBottom() {
//GIVEN
@@ -172,6 +181,7 @@ public void oWinsCrossingFromTopToBottom() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("X wins using a convoluted path")
public void xWinsUsingConvolutedPath() {
//GIVEN
@@ -194,6 +204,7 @@ public void xWinsUsingConvolutedPath() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("X wins using a spiral path")
public void xWinsUsingASpiralPath() {
//GIVEN
diff --git a/exercises/practice/crypto-square/.meta/config.json b/exercises/practice/crypto-square/.meta/config.json
index 83572a7b4..5f8c77cc7 100644
--- a/exercises/practice/crypto-square/.meta/config.json
+++ b/exercises/practice/crypto-square/.meta/config.json
@@ -21,6 +21,7 @@
"sshine",
"stkent",
"vdemeester",
+ "Xinri",
"Zaldrick"
],
"files": {
diff --git a/exercises/practice/crypto-square/.meta/tests.toml b/exercises/practice/crypto-square/.meta/tests.toml
index 085d142ea..94ef0819f 100644
--- a/exercises/practice/crypto-square/.meta/tests.toml
+++ b/exercises/practice/crypto-square/.meta/tests.toml
@@ -32,3 +32,8 @@ description = "8 character plaintext results in 3 chunks, the last one with a tr
[fbcb0c6d-4c39-4a31-83f6-c473baa6af80]
description = "54 character plaintext results in 7 chunks, the last two with trailing spaces"
+include = false
+
+[33fd914e-fa44-445b-8f38-ff8fbc9fe6e6]
+description = "54 character plaintext results in 8 chunks, the last two with trailing spaces"
+reimplements = "fbcb0c6d-4c39-4a31-83f6-c473baa6af80"
diff --git a/exercises/practice/crypto-square/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/crypto-square/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/crypto-square/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/crypto-square/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/crypto-square/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/crypto-square/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/crypto-square/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/crypto-square/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/crypto-square/gradlew b/exercises/practice/crypto-square/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/crypto-square/gradlew
+++ b/exercises/practice/crypto-square/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/crypto-square/gradlew.bat b/exercises/practice/crypto-square/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/crypto-square/gradlew.bat
+++ b/exercises/practice/crypto-square/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/crypto-square/src/test/java/CryptoSquareTest.java b/exercises/practice/crypto-square/src/test/java/CryptoSquareTest.java
index 59eb4fc70..9b9225487 100644
--- a/exercises/practice/crypto-square/src/test/java/CryptoSquareTest.java
+++ b/exercises/practice/crypto-square/src/test/java/CryptoSquareTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -6,6 +7,7 @@
public class CryptoSquareTest {
@Test
+ @DisplayName("empty plaintext results in an empty ciphertext")
public void emptyPlaintextResultsInEmptyCiphertext() {
CryptoSquare cryptoSquare = new CryptoSquare("");
String expectedOutput = "";
@@ -15,6 +17,7 @@ public void emptyPlaintextResultsInEmptyCiphertext() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("normalization results in empty plaintext")
public void normalizationResultsInEmptyCiphertext() {
CryptoSquare cryptoSquare = new CryptoSquare("... --- ...");
String expectedOutput = "";
@@ -24,6 +27,7 @@ public void normalizationResultsInEmptyCiphertext() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Lowercase")
public void lettersAreLowerCasedDuringEncryption() {
CryptoSquare cryptoSquare = new CryptoSquare("A");
String expectedOutput = "a";
@@ -33,6 +37,7 @@ public void lettersAreLowerCasedDuringEncryption() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Remove spaces")
public void spacesAreRemovedDuringEncryption() {
CryptoSquare cryptoSquare = new CryptoSquare(" b ");
String expectedOutput = "b";
@@ -42,6 +47,7 @@ public void spacesAreRemovedDuringEncryption() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Remove punctuation")
public void punctuationIsRemovedDuringEncryption() {
CryptoSquare cryptoSquare = new CryptoSquare("@1,%!");
String expectedOutput = "1";
@@ -51,6 +57,7 @@ public void punctuationIsRemovedDuringEncryption() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("9 character plaintext results in 3 chunks of 3 characters")
public void nineCharacterPlaintextResultsInThreeChunksOfThreeCharacters() {
CryptoSquare cryptoSquare = new CryptoSquare("This is fun!");
String expectedOutput = "tsf hiu isn";
@@ -60,6 +67,7 @@ public void nineCharacterPlaintextResultsInThreeChunksOfThreeCharacters() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("8 character plaintext results in 3 chunks, the last one with a trailing space")
public void eightCharacterPlaintextResultsInThreeChunksWithATrailingSpace() {
CryptoSquare cryptoSquare = new CryptoSquare("Chill out.");
String expectedOutput = "clu hlt io ";
@@ -69,7 +77,8 @@ public void eightCharacterPlaintextResultsInThreeChunksWithATrailingSpace() {
@Disabled("Remove to run test")
@Test
- public void fiftyFourCharacterPlaintextResultsInSevenChunksWithTrailingSpaces() {
+ @DisplayName("54 character plaintext results in 8 chunks, the last two with trailing spaces")
+ public void fiftyFourCharacterPlaintextResultsInEightChunksWithTrailingSpaces() {
CryptoSquare cryptoSquare = new CryptoSquare("If man was meant to stay on the ground, god would have " +
"given us roots.");
String expectedOutput = "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau ";
diff --git a/exercises/practice/custom-set/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/custom-set/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/custom-set/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/custom-set/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/custom-set/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/custom-set/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/custom-set/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/custom-set/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/custom-set/gradlew b/exercises/practice/custom-set/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/custom-set/gradlew
+++ b/exercises/practice/custom-set/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/custom-set/gradlew.bat b/exercises/practice/custom-set/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/custom-set/gradlew.bat
+++ b/exercises/practice/custom-set/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/custom-set/src/test/java/CustomSetTest.java b/exercises/practice/custom-set/src/test/java/CustomSetTest.java
index 4f32727c4..1032ecd50 100644
--- a/exercises/practice/custom-set/src/test/java/CustomSetTest.java
+++ b/exercises/practice/custom-set/src/test/java/CustomSetTest.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.Arrays;
@@ -9,6 +10,7 @@
public class CustomSetTest {
@Test
+ @DisplayName("Returns true if the set contains no elements")
public void setsWithNoElementsAreEmpty() {
CustomSet customSet = new CustomSet<>(Collections.emptyList());
assertThat(customSet.isEmpty()).isTrue();
@@ -16,6 +18,7 @@ public void setsWithNoElementsAreEmpty() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("sets with elements are not empty")
public void setsWithElementsAreNotEmpty() {
CustomSet customSet = new CustomSet<>(Collections.singletonList('1'));
assertThat(customSet.isEmpty()).isFalse();
@@ -23,6 +26,7 @@ public void setsWithElementsAreNotEmpty() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("nothing is contained in an empty set")
public void nothingIsContainedInAnEmptySet() {
CustomSet customSet = new CustomSet<>(Collections.emptyList());
assertThat(customSet.contains("1")).isFalse();
@@ -30,6 +34,7 @@ public void nothingIsContainedInAnEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("when the element is in the set")
public void whenTheElementIsInTheSet() {
CustomSet customSet = new CustomSet<>(Arrays.asList(1, 2, 3));
assertThat(customSet.contains(1)).isTrue();
@@ -37,6 +42,7 @@ public void whenTheElementIsInTheSet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("when the element is not in the set")
public void whenTheElementIsNotInTheSet() {
CustomSet customSet = new CustomSet<>(Arrays.asList('1', '2', '3'));
assertThat(customSet.contains('4')).isFalse();
@@ -44,6 +50,7 @@ public void whenTheElementIsNotInTheSet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("empty set is a subset of another empty set")
public void emptySetIsASubsetOfAnotherEmptySet() {
CustomSet customSet = new CustomSet<>(Collections.emptyList());
CustomSet secondCustomSet = new CustomSet<>(Collections.emptyList());
@@ -52,6 +59,7 @@ public void emptySetIsASubsetOfAnotherEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("empty set is a subset of non-empty set")
public void emptySetIsASubsetOfNonEmptySet() {
CustomSet customSet = new CustomSet<>(Collections.singletonList(1));
CustomSet secondCustomSet = new CustomSet<>(Collections.emptyList());
@@ -60,6 +68,7 @@ public void emptySetIsASubsetOfNonEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("non-empty set is not a subset of empty set")
public void nonEmptySetIsNotASubsetOfEmptySet() {
CustomSet customSet = new CustomSet<>(Collections.emptyList());
CustomSet secondCustomSet = new CustomSet<>(Collections.singletonList('1'));
@@ -68,6 +77,7 @@ public void nonEmptySetIsNotASubsetOfEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("set is a subset of set with exact same elements")
public void setIsASubsetOfSetWithExactSameElements() {
CustomSet customSet = new CustomSet<>(Arrays.asList("1", "2", "3"));
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList("1", "2", "3"));
@@ -76,6 +86,7 @@ public void setIsASubsetOfSetWithExactSameElements() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("set is a subset of larger set with same elements")
public void setIsASubsetOfLargerSetWithSameElements() {
CustomSet customSet = new CustomSet<>(Arrays.asList(4, 1, 2, 3));
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList(1, 2, 3));
@@ -84,6 +95,7 @@ public void setIsASubsetOfLargerSetWithSameElements() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("set is not a subset of set that does not contain its elements")
public void setIsNotASubsetOfSetThatDoesNotContainItsElements() {
CustomSet customSet = new CustomSet<>(Arrays.asList('4', '1', '3'));
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList('1', '2', '3'));
@@ -92,6 +104,7 @@ public void setIsNotASubsetOfSetThatDoesNotContainItsElements() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("the empty set is disjoint with itself")
public void theEmptySetIsDisjointWithItself() {
CustomSet customSet = new CustomSet<>(Collections.emptyList());
CustomSet secondCustomSet = new CustomSet<>(Collections.emptyList());
@@ -100,6 +113,7 @@ public void theEmptySetIsDisjointWithItself() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("empty set is disjoint with non-empty set")
public void emptySetIsDisjointWithNonEmptySet() {
CustomSet customSet = new CustomSet<>(Collections.emptyList());
CustomSet secondCustomSet = new CustomSet<>(Collections.singletonList(1));
@@ -108,6 +122,7 @@ public void emptySetIsDisjointWithNonEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("non-empty set is disjoint with empty set")
public void nonEmptySetIsDisjointWithEmptySet() {
CustomSet customSet = new CustomSet<>(Collections.singletonList('1'));
CustomSet secondCustomSet = new CustomSet<>(Collections.emptyList());
@@ -116,6 +131,7 @@ public void nonEmptySetIsDisjointWithEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("sets are not disjoint if they share an element")
public void setsAreNotDisjointIfTheyShareAnElement() {
CustomSet customSet = new CustomSet<>(Arrays.asList("1", "2"));
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList("2", "3"));
@@ -124,6 +140,7 @@ public void setsAreNotDisjointIfTheyShareAnElement() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("sets are disjoint if they share no elements")
public void setsAreDisjointIfTheyShareNoElements() {
CustomSet customSet = new CustomSet<>(Arrays.asList(1, 2));
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList(3, 4));
@@ -132,6 +149,7 @@ public void setsAreDisjointIfTheyShareNoElements() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("empty sets are equal")
public void emptySetsAreEqual() {
CustomSet customSet = new CustomSet<>(Collections.emptyList());
CustomSet secondCustomSet = new CustomSet<>(Collections.emptyList());
@@ -140,6 +158,7 @@ public void emptySetsAreEqual() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("empty set is not equal to non-empty set")
public void emptySetIsNotEqualToNonEmptySet() {
CustomSet customSet = new CustomSet<>(Collections.emptyList());
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList("1", "2", "3"));
@@ -148,6 +167,7 @@ public void emptySetIsNotEqualToNonEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("non-empty set is not equal to empty set")
public void nonEmptySetIsNotEqualToEmptySet() {
CustomSet customSet = new CustomSet<>(Arrays.asList(1, 2, 3));
CustomSet secondCustomSet = new CustomSet<>(Collections.emptyList());
@@ -156,6 +176,7 @@ public void nonEmptySetIsNotEqualToEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("sets with the same elements are equal")
public void setsWithTheSameElementsAreEqual() {
CustomSet customSet = new CustomSet<>(Arrays.asList('1', '2'));
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList('2', '1'));
@@ -164,6 +185,7 @@ public void setsWithTheSameElementsAreEqual() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("sets with different elements are not equal")
public void setsWithDifferentElementsAreNotEqual() {
CustomSet customSet = new CustomSet<>(Arrays.asList("1", "2", "3"));
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList("1", "2", "4"));
@@ -172,6 +194,7 @@ public void setsWithDifferentElementsAreNotEqual() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("set is not equal to larger set with same elements")
public void setIsNotEqualToLargerSetWithSameElements() {
CustomSet customSet = new CustomSet<>(Arrays.asList("1", "2", "3"));
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList("1", "2", "3", "4"));
@@ -180,6 +203,7 @@ public void setIsNotEqualToLargerSetWithSameElements() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("set is equal to a set constructed from an array with duplicates")
public void secondSetWithDuplicatesIsEqualToFirstSet() {
CustomSet customSet = new CustomSet<>(Collections.singletonList("1"));
CustomSet secondCustomSet = new CustomSet<>(Arrays.asList("1", "1"));
@@ -188,6 +212,7 @@ public void secondSetWithDuplicatesIsEqualToFirstSet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("difference removes all duplicates in the first set")
public void firstSetWithDuplicatesIsEqualToSecondSet() {
CustomSet customSet = new CustomSet<>(Arrays.asList("1", "1"));
CustomSet secondCustomSet = new CustomSet<>(Collections.singletonList("1"));
@@ -196,6 +221,7 @@ public void firstSetWithDuplicatesIsEqualToSecondSet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add to empty set")
public void addToEmptySet() {
int element = 3;
CustomSet expected = new CustomSet<>(Collections.unmodifiableList(Collections.singletonList(element)));
@@ -211,6 +237,7 @@ public void addToEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("add to non-empty set")
public void addToNonEmptySet() {
char element = '3';
CustomSet expected = new CustomSet<>(Collections.unmodifiableList(
@@ -226,6 +253,7 @@ public void addToNonEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("adding an existing element does not change the set")
public void addingAnExistingElementDoesNotChangeTheSet() {
String element = "3";
CustomSet expected = new CustomSet<>(Collections.unmodifiableList(Arrays.asList("1", "2", "3")));
@@ -239,6 +267,7 @@ public void addingAnExistingElementDoesNotChangeTheSet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("intersection of two empty sets is an empty set")
public void intersectionOfTwoEmptySetsIsAnEmptySet() {
CustomSet actual = new CustomSet(Collections.emptyList())
.getIntersection(new CustomSet<>(Collections.emptyList()));
@@ -249,6 +278,7 @@ public void intersectionOfTwoEmptySetsIsAnEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("intersection of an empty set and non-empty set is an empty set")
public void intersectionOfAnEmptySetAndNonEmptySetIsAnEmptySet() {
CustomSet actual = new CustomSet(Collections.emptyList())
.getIntersection(new CustomSet<>(Arrays.asList('3', '2', '5')));
@@ -259,6 +289,7 @@ public void intersectionOfAnEmptySetAndNonEmptySetIsAnEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("intersection of a non-empty set and an empty set is an empty set")
public void intersectionOfANonEmptySetAndAnEmptySetIsAnEmptySet() {
CustomSet actual = new CustomSet<>(Arrays.asList("1", "2", "3", "4"))
.getIntersection(new CustomSet<>(Collections.emptyList()));
@@ -270,6 +301,7 @@ public void intersectionOfANonEmptySetAndAnEmptySetIsAnEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("intersection of two sets with no shared elements is an empty set")
public void intersectionOfTwoSetsWithNoSharedElementsIsAnEmptySet() {
CustomSet actual = new CustomSet<>(Arrays.asList(1, 2, 3))
.getIntersection(new CustomSet<>(Arrays.asList(4, 5, 6)));
@@ -280,6 +312,7 @@ public void intersectionOfTwoSetsWithNoSharedElementsIsAnEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("intersection of two sets with shared elements is a set of the shared elements")
public void intersectionOfTwoSetsWithSharedElementsIsASetOfTheSharedElements() {
CustomSet expected = new CustomSet<>(Collections.unmodifiableList(Arrays.asList('2', '3')));
CustomSet actual = new CustomSet<>(Arrays.asList('1', '2', '3', '4'))
@@ -292,6 +325,7 @@ public void intersectionOfTwoSetsWithSharedElementsIsASetOfTheSharedElements() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("difference of two empty sets is an empty set")
public void differenceOfTwoEmptySetsIsAnEmptySet() {
CustomSet actual = new CustomSet(Collections.emptyList())
.getDifference(new CustomSet<>(Collections.emptyList()));
@@ -302,6 +336,7 @@ public void differenceOfTwoEmptySetsIsAnEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("difference of empty set and non-empty set is an empty set")
public void differenceOfAnEmptySetAndNonEmptySetIsAnEmptySet() {
CustomSet actual = new CustomSet(Collections.emptyList())
.getDifference(new CustomSet<>(Arrays.asList(3, 2, 5)));
@@ -312,6 +347,7 @@ public void differenceOfAnEmptySetAndNonEmptySetIsAnEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("difference of a non-empty set and an empty set is the non-empty set")
public void differenceOfANonEmptySetAndAnEmptySetIsTheNonEmptySet() {
CustomSet expected = new CustomSet<>(Collections.unmodifiableList(
Arrays.asList('1', '2', '3', '4')));
@@ -325,6 +361,7 @@ public void differenceOfANonEmptySetAndAnEmptySetIsTheNonEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("difference of two non-empty sets is a set of elements that are only in the first set")
public void differenceOfTwoNonEmptySetsIsASetOfElementsThatAreOnlyInTheFirstSet() {
CustomSet expected = new CustomSet<>(Collections.unmodifiableList(Arrays.asList("1", "3")));
CustomSet actual = new CustomSet<>(Arrays.asList("3", "2", "1"))
@@ -338,6 +375,7 @@ public void differenceOfTwoNonEmptySetsIsASetOfElementsThatAreOnlyInTheFirstSet(
@Disabled("Remove to run test")
@Test
+ @DisplayName("union of empty sets is an empty set")
public void unionOfTwoEmptySetsIsAnEmptySet() {
CustomSet actual = new CustomSet(Collections.emptyList())
.getUnion(new CustomSet<>(Collections.emptyList()));
@@ -348,6 +386,7 @@ public void unionOfTwoEmptySetsIsAnEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("union of an empty set and non-empty set is the non-empty set")
public void unionOfAnEmptySetAndNonEmptySetIsTheNonEmptySet() {
CustomSet expected = new CustomSet<>(Collections.unmodifiableList(Collections.singletonList('2')));
CustomSet actual = new CustomSet(Collections.emptyList())
@@ -360,6 +399,7 @@ public void unionOfAnEmptySetAndNonEmptySetIsTheNonEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("union of a non-empty set and empty set is the non-empty set")
public void unionOfANonEmptySetAndAnEmptySetIsTheNonEmptySet() {
CustomSet expected = new CustomSet<>(Collections.unmodifiableList(Arrays.asList("1", "3")));
CustomSet actual = new CustomSet<>(Arrays.asList("1", "3"))
@@ -372,6 +412,7 @@ public void unionOfANonEmptySetAndAnEmptySetIsTheNonEmptySet() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("union of non-empty sets contains all unique elements")
public void unionOfTwoNonEmptySetsContainsAllUniqueElements() {
CustomSet expected = new CustomSet<>(Collections.unmodifiableList(Arrays.asList(3, 2, 1)));
CustomSet actual = new CustomSet<>(Arrays.asList(1, 3))
diff --git a/exercises/practice/darts/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/darts/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/darts/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/darts/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/darts/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/darts/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/darts/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/darts/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/darts/gradlew b/exercises/practice/darts/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/darts/gradlew
+++ b/exercises/practice/darts/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/darts/gradlew.bat b/exercises/practice/darts/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/darts/gradlew.bat
+++ b/exercises/practice/darts/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/darts/src/test/java/DartsTest.java b/exercises/practice/darts/src/test/java/DartsTest.java
index f6e10baed..45376bfe4 100644
--- a/exercises/practice/darts/src/test/java/DartsTest.java
+++ b/exercises/practice/darts/src/test/java/DartsTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -7,60 +8,70 @@ public class DartsTest {
Darts darts = new Darts();
@Test
+ @DisplayName("Missed target")
public void missedTarget() {
assertThat(darts.score(-9, 9)).isEqualTo(0);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("On the outer circle")
public void onTheOuterCircle() {
assertThat(darts.score(0, 10)).isEqualTo(1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("On the middle circle")
public void onTheMiddleCircle() {
assertThat(darts.score(-5, 0)).isEqualTo(5);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("On the inner circle")
public void onTheInnerCircle() {
assertThat(darts.score(0, -1)).isEqualTo(10);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Exactly on center")
public void exactlyOnCentre() {
assertThat(darts.score(0, 0)).isEqualTo(10);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Near the center")
public void nearTheCentre() {
assertThat(darts.score(-0.1, -0.1)).isEqualTo(10);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Just within the inner circle")
public void justWithinTheInnerCircle() {
assertThat(darts.score(0.7, 0.7)).isEqualTo(10);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Just outside the inner circle")
public void justOutsideTheInnerCircle() {
assertThat(darts.score(0.8, -0.8)).isEqualTo(5);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Just within the middle circle")
public void justWithinTheMiddleCircle() {
assertThat(darts.score(-3.5, 3.5)).isEqualTo(5);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Just outside the middle circle")
public void justOutsideTheMiddleCircle() {
assertThat(darts.score(-3.6, -3.6)).isEqualTo(1);
}
@@ -68,18 +79,21 @@ public void justOutsideTheMiddleCircle() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Just within the outer circle")
public void justWithinTheOuterCircle() {
assertThat(darts.score(-7.0, 7.0)).isEqualTo(1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Just outside the outer circle")
public void justOutsideTheOuterCircle() {
assertThat(darts.score(7.1, -7.1)).isEqualTo(0);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Asymmetric position between the inner and middle circles")
public void asymmetricPositionBetweenTheInnerAndMiddleCircles() {
assertThat(darts.score(0.5, -4)).isEqualTo(5);
}
diff --git a/exercises/practice/diamond/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/diamond/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/diamond/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/diamond/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/diamond/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/diamond/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/diamond/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/diamond/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/diamond/gradlew b/exercises/practice/diamond/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/diamond/gradlew
+++ b/exercises/practice/diamond/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/diamond/gradlew.bat b/exercises/practice/diamond/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/diamond/gradlew.bat
+++ b/exercises/practice/diamond/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/diamond/src/test/java/DiamondPrinterTest.java b/exercises/practice/diamond/src/test/java/DiamondPrinterTest.java
index 3388aeefe..6608faeac 100644
--- a/exercises/practice/diamond/src/test/java/DiamondPrinterTest.java
+++ b/exercises/practice/diamond/src/test/java/DiamondPrinterTest.java
@@ -1,7 +1,8 @@
import static org.assertj.core.api.Assertions.assertThat;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class DiamondPrinterTest {
@@ -14,6 +15,7 @@ public void setUp() {
}
@Test
+ @DisplayName("Degenerate case with a single 'A' row")
public void testOneByOneDiamond() {
assertThat(diamondPrinter.printToList('A'))
.containsExactly("A");
@@ -21,6 +23,7 @@ public void testOneByOneDiamond() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Degenerate case with no row containing 3 distinct groups of spaces")
public void testTwoByTwoDiamond() {
assertThat(diamondPrinter.printToList('B'))
.containsExactly(
@@ -31,6 +34,7 @@ public void testTwoByTwoDiamond() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Smallest non-degenerate case with odd diamond side length")
public void testThreeByThreeDiamond() {
assertThat(diamondPrinter.printToList('C'))
.containsExactly(
@@ -43,6 +47,7 @@ public void testThreeByThreeDiamond() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Smallest non-degenerate case with even diamond side length")
public void testFourByFourDiamond() {
assertThat(diamondPrinter.printToList('D'))
.containsExactly(
@@ -57,6 +62,7 @@ public void testFourByFourDiamond() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Largest possible diamond")
public void testFullDiamond() {
assertThat(diamondPrinter.printToList('Z'))
.containsExactly(
diff --git a/exercises/practice/difference-of-squares/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/difference-of-squares/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/difference-of-squares/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/difference-of-squares/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/difference-of-squares/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/difference-of-squares/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/difference-of-squares/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/difference-of-squares/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/difference-of-squares/gradlew b/exercises/practice/difference-of-squares/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/difference-of-squares/gradlew
+++ b/exercises/practice/difference-of-squares/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/difference-of-squares/gradlew.bat b/exercises/practice/difference-of-squares/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/difference-of-squares/gradlew.bat
+++ b/exercises/practice/difference-of-squares/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/difference-of-squares/src/test/java/DifferenceOfSquaresCalculatorTest.java b/exercises/practice/difference-of-squares/src/test/java/DifferenceOfSquaresCalculatorTest.java
index 3df042fdf..93d3af7a4 100644
--- a/exercises/practice/difference-of-squares/src/test/java/DifferenceOfSquaresCalculatorTest.java
+++ b/exercises/practice/difference-of-squares/src/test/java/DifferenceOfSquaresCalculatorTest.java
@@ -1,5 +1,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -14,6 +15,7 @@ public void setUp() {
}
@Test
+ @DisplayName("square of sum 1")
public void testSquareOfSumUpToOne() {
int expected = 1;
int actual = calculator.computeSquareOfSumTo(1);
@@ -22,6 +24,7 @@ public void testSquareOfSumUpToOne() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("square of sum 5")
public void testSquareOfSumUpToFive() {
int expected = 225;
int actual = calculator.computeSquareOfSumTo(5);
@@ -30,6 +33,7 @@ public void testSquareOfSumUpToFive() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("square of sum 100")
public void testSquareOfSumUpToHundred() {
int expected = 25502500;
int actual = calculator.computeSquareOfSumTo(100);
@@ -38,6 +42,7 @@ public void testSquareOfSumUpToHundred() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("sum of squares 1")
public void testSumOfSquaresUpToOne() {
int expected = 1;
int actual = calculator.computeSumOfSquaresTo(1);
@@ -46,6 +51,7 @@ public void testSumOfSquaresUpToOne() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("sum of squares 5")
public void testSumOfSquaresUpToFive() {
int expected = 55;
int actual = calculator.computeSumOfSquaresTo(5);
@@ -54,6 +60,7 @@ public void testSumOfSquaresUpToFive() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("sum of squares 100")
public void testSumOfSquaresUpToHundred() {
int expected = 338350;
int actual = calculator.computeSumOfSquaresTo(100);
@@ -62,6 +69,7 @@ public void testSumOfSquaresUpToHundred() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("difference of squares 1")
public void testDifferenceOfSquaresUpToOne() {
int expected = 0;
int actual = calculator.computeDifferenceOfSquares(1);
@@ -70,6 +78,7 @@ public void testDifferenceOfSquaresUpToOne() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("difference of squares 5")
public void testDifferenceOfSquaresUpToFive() {
int expected = 170;
int actual = calculator.computeDifferenceOfSquares(5);
@@ -78,6 +87,7 @@ public void testDifferenceOfSquaresUpToFive() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("difference of squares 100")
public void testDifferenceOfSquaresUpToHundred() {
int expected = 25164150;
int actual = calculator.computeDifferenceOfSquares(100);
diff --git a/exercises/practice/dnd-character/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/dnd-character/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/dnd-character/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/dnd-character/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/dnd-character/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/dnd-character/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/dnd-character/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/dnd-character/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/dnd-character/gradlew b/exercises/practice/dnd-character/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/dnd-character/gradlew
+++ b/exercises/practice/dnd-character/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/dnd-character/gradlew.bat b/exercises/practice/dnd-character/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/dnd-character/gradlew.bat
+++ b/exercises/practice/dnd-character/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/dnd-character/src/test/java/DnDCharacterTest.java b/exercises/practice/dnd-character/src/test/java/DnDCharacterTest.java
index 1c9afc921..c54ad52ac 100644
--- a/exercises/practice/dnd-character/src/test/java/DnDCharacterTest.java
+++ b/exercises/practice/dnd-character/src/test/java/DnDCharacterTest.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.List;
@@ -10,150 +11,175 @@ public class DnDCharacterTest {
private DnDCharacter dndCharacter = new DnDCharacter();
@Test
+ @DisplayName("ability modifier for score 3 is -4")
public void testAbilityModifierForScore3IsNegative4() {
assertThat(dndCharacter.modifier(3)).isEqualTo(-4);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 4 is -3")
public void testAbilityModifierForScore4IsNegative3() {
assertThat(dndCharacter.modifier(4)).isEqualTo(-3);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 5 is -3")
public void testAbilityModifierForScore5IsNegative3() {
assertThat(dndCharacter.modifier(5)).isEqualTo(-3);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 6 is -2")
public void testAbilityModifierForScore6IsNegative2() {
assertThat(dndCharacter.modifier(6)).isEqualTo(-2);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 7 is -2")
public void testAbilityModifierForScore7IsNegative2() {
assertThat(dndCharacter.modifier(7)).isEqualTo(-2);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 8 is -1")
public void testAbilityModifierForScore8IsNegative1() {
assertThat(dndCharacter.modifier(8)).isEqualTo(-1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 9 is -1")
public void testAbilityModifierForScore9IsNegative1() {
assertThat(dndCharacter.modifier(9)).isEqualTo(-1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 10 is 0")
public void testAbilityModifierForScore10Is0() {
assertThat(dndCharacter.modifier(10)).isEqualTo(0);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 11 is 0")
public void testAbilityModifierForScore11Is0() {
assertThat(dndCharacter.modifier(11)).isEqualTo(0);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 12 is +1")
public void testAbilityModifierForScore12Is1() {
assertThat(dndCharacter.modifier(12)).isEqualTo(1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 13 is +1")
public void testAbilityModifierForScore13Is1() {
assertThat(dndCharacter.modifier(13)).isEqualTo(1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 14 is +2")
public void testAbilityModifierForScore14Is2() {
assertThat(dndCharacter.modifier(14)).isEqualTo(2);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 15 is +2")
public void testAbilityModifierForScore15Is2() {
assertThat(dndCharacter.modifier(15)).isEqualTo(2);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 16 is +3")
public void testAbilityModifierForScore16Is3() {
assertThat(dndCharacter.modifier(16)).isEqualTo(3);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 17 is +3")
public void testAbilityModifierForScore17Is3() {
assertThat(dndCharacter.modifier(17)).isEqualTo(3);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("ability modifier for score 18 is +4")
public void testAbilityModifierForScore18Is4() {
assertThat(dndCharacter.modifier(18)).isEqualTo(4);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Rolling uses 4 dice")
public void test4DiceWereUsedForRollingScores() {
assertThat(dndCharacter.rollDice().size()).isEqualTo(4);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Dice values are between 1 and 6 inclusive")
public void testDiceValuesBetween1And6() {
assertThat(dndCharacter.rollDice()).allMatch(d -> d >= 1 && d <= 6);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Ability uses 3 largest numbers from scores in descending order")
public void testAbilityCalculationsUses3LargestNumbersFromScoresInDescendingOrder() {
assertThat(dndCharacter.ability(List.of(4, 3, 2, 1))).isEqualTo(9);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Ability uses 3 largest numbers from scores in ascending order")
public void testAbilityCalculationsUses3LargestNumbersFromFromScoresInAscendingOrder() {
assertThat(dndCharacter.ability(List.of(1, 2, 3, 4))).isEqualTo(9);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Ability uses 3 largest numbers from scores in random order")
public void testAbilityCalculationsUses3LargestNumbersFromScoresInRandomOrder() {
assertThat(dndCharacter.ability(List.of(2, 4, 3, 1))).isEqualTo(9);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Ability with all lowest equal numbers yields 3")
public void testAbilityCalculationsWithLowestEqualNumbers() {
assertThat(dndCharacter.ability(List.of(1, 1, 1, 1))).isEqualTo(3);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Ability with all highest equal numbers yields 18")
public void testAbilityCalculationsWithHighestEqualNumbers() {
assertThat(dndCharacter.ability(List.of(6, 6, 6, 6))).isEqualTo(18);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Ability calculation with two lowest numbers")
public void testAbilityCalculationsWithTwoLowestNumbers() {
assertThat(dndCharacter.ability(List.of(3, 5, 3, 4))).isEqualTo(12);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Ability calculation does not mutate input scores")
public void testAbilityCalculationDoesNotChangeInputScores() {
List scores = List.of(1, 2, 3, 4);
dndCharacter.ability(scores);
@@ -164,6 +190,7 @@ public void testAbilityCalculationDoesNotChangeInputScores() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("random character is valid")
public void testRandomCharacterIsValid() {
for (int i = 0; i < 1000; i++) {
DnDCharacter character = new DnDCharacter();
@@ -179,6 +206,7 @@ public void testRandomCharacterIsValid() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("each ability is only calculated once")
public void testEachAbilityIsOnlyCalculatedOnce() {
assertThat(dndCharacter.getStrength()).isEqualTo(dndCharacter.getStrength());
assertThat(dndCharacter.getDexterity()).isEqualTo(dndCharacter.getDexterity());
@@ -190,6 +218,7 @@ public void testEachAbilityIsOnlyCalculatedOnce() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Each randomly created character should be unique in attributes")
public void testUniqueCharacterIsCreated() {
DnDCharacter uniqueDnDCharacter = new DnDCharacter();
for (int i = 0; i < 1000; i++) {
diff --git a/exercises/practice/dominoes/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/dominoes/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/dominoes/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/dominoes/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/dominoes/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/dominoes/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/dominoes/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/dominoes/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/dominoes/gradlew b/exercises/practice/dominoes/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/dominoes/gradlew
+++ b/exercises/practice/dominoes/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/dominoes/gradlew.bat b/exercises/practice/dominoes/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/dominoes/gradlew.bat
+++ b/exercises/practice/dominoes/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/dominoes/src/test/java/DominoesTest.java b/exercises/practice/dominoes/src/test/java/DominoesTest.java
index 76f2e4931..d1570eb77 100644
--- a/exercises/practice/dominoes/src/test/java/DominoesTest.java
+++ b/exercises/practice/dominoes/src/test/java/DominoesTest.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.ArrayList;
@@ -12,6 +13,7 @@
public class DominoesTest {
@Test
+ @DisplayName("empty input = empty output")
public void emtpyInputEmptyOutputTest() throws ChainNotFoundException {
Dominoes dominoes = new Dominoes();
@@ -24,6 +26,7 @@ public void emtpyInputEmptyOutputTest() throws ChainNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("singleton input = singleton output")
public void singletonInputSingletonOutput() throws ChainNotFoundException {
Dominoes dominoes = new Dominoes();
@@ -37,6 +40,7 @@ public void singletonInputSingletonOutput() throws ChainNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("singleton that can't be chained")
public void singletonCantBeChainedTest() {
Dominoes dominoes = new Dominoes();
@@ -50,6 +54,7 @@ public void singletonCantBeChainedTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("three elements")
public void threeElementsTest() throws ChainNotFoundException {
Dominoes dominoes = new Dominoes();
@@ -63,6 +68,7 @@ public void threeElementsTest() throws ChainNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can reverse dominoes")
public void canReverseDominoesTest() throws ChainNotFoundException {
Dominoes dominoes = new Dominoes();
@@ -76,6 +82,7 @@ public void canReverseDominoesTest() throws ChainNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can't be chained")
public void cantBeChainedTest() {
Dominoes dominoes = new Dominoes();
@@ -89,6 +96,7 @@ public void cantBeChainedTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("disconnected - simple")
public void disconnectedSimpleTest() {
Dominoes dominoes = new Dominoes();
@@ -102,6 +110,7 @@ public void disconnectedSimpleTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("disconnected - double loop")
public void disconnectedDoubleLoopTest() {
Dominoes dominoes = new Dominoes();
@@ -115,6 +124,7 @@ public void disconnectedDoubleLoopTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("disconnected - single isolated")
public void disconnectedSingleIsolatedTest() {
Dominoes dominoes = new Dominoes();
@@ -128,6 +138,7 @@ public void disconnectedSingleIsolatedTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("need backtrack")
public void needBacktrackTest() throws ChainNotFoundException {
Dominoes dominoes = new Dominoes();
@@ -142,6 +153,7 @@ public void needBacktrackTest() throws ChainNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("separate loops")
public void separateLoopsTest() throws ChainNotFoundException {
Dominoes dominoes = new Dominoes();
@@ -156,6 +168,7 @@ public void separateLoopsTest() throws ChainNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("nine elements")
public void nineElementsTest() throws ChainNotFoundException {
Dominoes dominoes = new Dominoes();
Domino[] dominoesArray = {new Domino(1, 2), new Domino(5, 3), new Domino(3, 1),
@@ -170,6 +183,7 @@ public void nineElementsTest() throws ChainNotFoundException {
@Disabled("Remove to run test")
@Test
+ @DisplayName("separate three-domino loops")
public void separateThreeDominoLoopsTest() {
Dominoes dominoes = new Dominoes();
diff --git a/exercises/practice/dot-dsl/.docs/instructions.md b/exercises/practice/dot-dsl/.docs/instructions.md
index b3a63996d..5e65ebef9 100644
--- a/exercises/practice/dot-dsl/.docs/instructions.md
+++ b/exercises/practice/dot-dsl/.docs/instructions.md
@@ -22,7 +22,7 @@ Write a Domain Specific Language similar to the Graphviz dot language.
Our DSL is similar to the Graphviz dot language in that our DSL will be used to create graph data structures.
However, unlike the DOT Language, our DSL will be an internal DSL for use only in our language.
-More information about the difference between internal and external DSLs can be found [here][fowler-dsl].
+[Learn more about the difference between internal and external DSLs][fowler-dsl].
[dsl]: https://en.wikipedia.org/wiki/Domain-specific_language
[dot-language]: https://en.wikipedia.org/wiki/DOT_(graph_description_language)
diff --git a/exercises/practice/dot-dsl/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/dot-dsl/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/dot-dsl/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/dot-dsl/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/dot-dsl/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/dot-dsl/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/dot-dsl/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/dot-dsl/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/dot-dsl/gradlew b/exercises/practice/dot-dsl/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/dot-dsl/gradlew
+++ b/exercises/practice/dot-dsl/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/dot-dsl/gradlew.bat b/exercises/practice/dot-dsl/gradlew.bat
index 93e3f59f1..c4bdd3ab8 100644
--- a/exercises/practice/dot-dsl/gradlew.bat
+++ b/exercises/practice/dot-dsl/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/eliuds-eggs/.docs/introduction.md b/exercises/practice/eliuds-eggs/.docs/introduction.md
index 819897480..2b2e5c43d 100644
--- a/exercises/practice/eliuds-eggs/.docs/introduction.md
+++ b/exercises/practice/eliuds-eggs/.docs/introduction.md
@@ -58,7 +58,7 @@ The position information encoding is calculated as follows:
### Decimal number on the display
-16
+8
### Actual eggs in the coop
diff --git a/exercises/practice/eliuds-eggs/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/eliuds-eggs/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/eliuds-eggs/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/eliuds-eggs/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/eliuds-eggs/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/eliuds-eggs/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/eliuds-eggs/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/eliuds-eggs/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/eliuds-eggs/gradlew b/exercises/practice/eliuds-eggs/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/eliuds-eggs/gradlew
+++ b/exercises/practice/eliuds-eggs/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/eliuds-eggs/gradlew.bat b/exercises/practice/eliuds-eggs/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/eliuds-eggs/gradlew.bat
+++ b/exercises/practice/eliuds-eggs/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/error-handling/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/error-handling/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/error-handling/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/error-handling/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/error-handling/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/error-handling/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/error-handling/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/error-handling/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/error-handling/gradlew b/exercises/practice/error-handling/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/error-handling/gradlew
+++ b/exercises/practice/error-handling/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/error-handling/gradlew.bat b/exercises/practice/error-handling/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/error-handling/gradlew.bat
+++ b/exercises/practice/error-handling/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/error-handling/src/test/java/ErrorHandlingTest.java b/exercises/practice/error-handling/src/test/java/ErrorHandlingTest.java
index c7864c7ad..7459b687f 100644
--- a/exercises/practice/error-handling/src/test/java/ErrorHandlingTest.java
+++ b/exercises/practice/error-handling/src/test/java/ErrorHandlingTest.java
@@ -1,16 +1,18 @@
-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;
import java.util.Optional;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
public class ErrorHandlingTest {
private ErrorHandling errorHandling = new ErrorHandling();
@Test
+ @DisplayName("Throws IllegalArgumentException")
public void testThrowIllegalArgumentException() {
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingIllegalArgumentException());
@@ -18,6 +20,7 @@ public void testThrowIllegalArgumentException() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Throws IllegalArgumentException with provided detail message")
public void testThrowIllegalArgumentExceptionWithDetailMessage() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingIllegalArgumentExceptionWithDetailMessage(
@@ -27,6 +30,7 @@ public void testThrowIllegalArgumentExceptionWithDetailMessage() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Throws any checked exception")
public void testThrowAnyCheckedException() {
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingAnyCheckedException())
@@ -35,6 +39,7 @@ public void testThrowAnyCheckedException() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Throws any checked exception with provided detail message")
public void testThrowAnyCheckedExceptionWithDetailMessage() {
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingAnyCheckedExceptionWithDetailMessage(
@@ -45,6 +50,7 @@ public void testThrowAnyCheckedExceptionWithDetailMessage() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Throws any unchecked exception")
public void testThrowAnyUncheckedException() {
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingAnyUncheckedException());
@@ -52,6 +58,7 @@ public void testThrowAnyUncheckedException() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Throws any unchecked exception with provided detail message")
public void testThrowAnyUncheckedExceptionWithDetailMessage() {
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingAnyUncheckedExceptionWithDetailMessage(
@@ -61,6 +68,7 @@ public void testThrowAnyUncheckedExceptionWithDetailMessage() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Throws custom checked exception")
public void testThrowCustomCheckedException() {
assertThatExceptionOfType(CustomCheckedException.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingCustomCheckedException());
@@ -68,6 +76,7 @@ public void testThrowCustomCheckedException() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Throws custom checked exception with provided detail message")
public void testThrowCustomCheckedExceptionWithDetailMessage() {
assertThatExceptionOfType(CustomCheckedException.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingCustomCheckedExceptionWithDetailMessage(
@@ -77,6 +86,7 @@ public void testThrowCustomCheckedExceptionWithDetailMessage() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Throws custom unchecked exception")
public void testThrowCustomUncheckedException() {
assertThatExceptionOfType(CustomUncheckedException.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingCustomUncheckedException());
@@ -84,6 +94,7 @@ public void testThrowCustomUncheckedException() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Throws custom unchecked exception with provided detail message")
public void testThrowCustomUncheckedExceptionWithDetailMessage() {
assertThatExceptionOfType(CustomUncheckedException.class)
.isThrownBy(() -> errorHandling.handleErrorByThrowingCustomUncheckedExceptionWithDetailMessage(
@@ -93,6 +104,7 @@ public void testThrowCustomUncheckedExceptionWithDetailMessage() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Handles error by throwing Optional instance")
public void testReturnOptionalInstance() {
Optional successfulResult = errorHandling.handleErrorByReturningOptionalInstance("1");
assertThat(successfulResult).isPresent().hasValue(1);
diff --git a/exercises/practice/etl/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/etl/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/etl/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/etl/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/etl/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/etl/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/etl/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/etl/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/etl/gradlew b/exercises/practice/etl/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/etl/gradlew
+++ b/exercises/practice/etl/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/etl/gradlew.bat b/exercises/practice/etl/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/etl/gradlew.bat
+++ b/exercises/practice/etl/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/etl/src/test/java/EtlTest.java b/exercises/practice/etl/src/test/java/EtlTest.java
index c25755690..4ef9292aa 100644
--- a/exercises/practice/etl/src/test/java/EtlTest.java
+++ b/exercises/practice/etl/src/test/java/EtlTest.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.Arrays;
@@ -14,6 +15,7 @@ public class EtlTest {
private final Etl etl = new Etl();
@Test
+ @DisplayName("single letter")
public void testTransformOneValue() {
Map> old = new HashMap>() {
{
@@ -34,6 +36,7 @@ public void testTransformOneValue() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("single score with multiple letters")
public void testTransformMoreValues() {
Map> old = new HashMap>() {
{
@@ -58,6 +61,7 @@ public void testTransformMoreValues() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("multiple scores with multiple letters")
public void testMoreKeys() {
Map> old = new HashMap>() {
{
@@ -82,6 +86,7 @@ public void testMoreKeys() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("multiple scores with differing numbers of letters")
public void testFullDataset() {
Map> old = new HashMap>() {
{
diff --git a/exercises/practice/flatten-array/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/flatten-array/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/flatten-array/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/flatten-array/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/flatten-array/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/flatten-array/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/flatten-array/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/flatten-array/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/flatten-array/gradlew b/exercises/practice/flatten-array/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/flatten-array/gradlew
+++ b/exercises/practice/flatten-array/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/flatten-array/gradlew.bat b/exercises/practice/flatten-array/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/flatten-array/gradlew.bat
+++ b/exercises/practice/flatten-array/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/flatten-array/src/test/java/FlattenerTest.java b/exercises/practice/flatten-array/src/test/java/FlattenerTest.java
index a9f94e280..2a5fb4323 100644
--- a/exercises/practice/flatten-array/src/test/java/FlattenerTest.java
+++ b/exercises/practice/flatten-array/src/test/java/FlattenerTest.java
@@ -1,5 +1,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static java.util.Arrays.asList;
@@ -17,6 +18,7 @@ public void setUp() {
}
@Test
+ @DisplayName("empty")
public void testEmpty() {
assertThat(flattener.flatten(emptyList()))
.isEmpty();
@@ -24,6 +26,7 @@ public void testEmpty() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("no nesting")
public void testFlatListIsPreserved() {
assertThat(flattener.flatten(asList(0, '1', "two")))
.containsExactly(0, '1', "two");
@@ -31,6 +34,7 @@ public void testFlatListIsPreserved() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("flattens a nested array")
public void testNestedList() {
assertThat(flattener.flatten(singletonList(emptyList())))
.isEmpty();
@@ -38,6 +42,7 @@ public void testNestedList() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("flattens array with just integers present")
public void testASingleLevelOfNestingWithNoNulls() {
assertThat(flattener.flatten(asList(1, asList('2', 3, 4, 5, "six", "7"), 8)))
.containsExactly(1, '2', 3, 4, 5, "six", "7", 8);
@@ -45,6 +50,7 @@ public void testASingleLevelOfNestingWithNoNulls() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("5 level nesting")
public void testFiveLevelsOfNestingWithNoNulls() {
assertThat(flattener.flatten(
asList(0,
@@ -59,6 +65,7 @@ public void testFiveLevelsOfNestingWithNoNulls() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("6 level nesting")
public void testSixLevelsOfNestingWithNoNulls() {
assertThat(flattener.flatten(
asList("one",
@@ -71,6 +78,7 @@ public void testSixLevelsOfNestingWithNoNulls() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("null values are omitted from the final result")
public void testNullValuesAreOmitted() {
assertThat(flattener.flatten(asList("1", "two", null)))
.containsExactly("1", "two");
@@ -78,6 +86,7 @@ public void testNullValuesAreOmitted() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("consecutive null values at the front of the list are omitted from the final result")
public void testConsecutiveNullValuesAtFrontOfListAreOmitted() {
assertThat(flattener.flatten(asList(null, null, 3)))
.containsExactly(3);
@@ -85,6 +94,7 @@ public void testConsecutiveNullValuesAtFrontOfListAreOmitted() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("consecutive null values in the middle of the list are omitted from the final result")
public void testConsecutiveNullValuesInMiddleOfListAreOmitted() {
assertThat(flattener.flatten(asList(1, null, null, "4")))
.containsExactly(1, "4");
@@ -92,6 +102,7 @@ public void testConsecutiveNullValuesInMiddleOfListAreOmitted() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("6 level nest list with null values")
public void testSixLevelsOfNestingWithNulls() {
assertThat(flattener.flatten(
asList("0",
@@ -107,6 +118,7 @@ public void testSixLevelsOfNestingWithNulls() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("all values in nested list are null")
public void testNestedListsFullOfNullsOnly() {
assertThat(flattener.flatten(
asList(null,
diff --git a/exercises/practice/flower-field/.docs/instructions.md b/exercises/practice/flower-field/.docs/instructions.md
new file mode 100644
index 000000000..bbdae0c2c
--- /dev/null
+++ b/exercises/practice/flower-field/.docs/instructions.md
@@ -0,0 +1,26 @@
+# Instructions
+
+Your task is to add flower counts to empty squares in a completed Flower Field garden.
+The garden itself is a rectangle board composed of squares that are either empty (`' '`) or a flower (`'*'`).
+
+For each empty square, count the number of flowers adjacent to it (horizontally, vertically, diagonally).
+If the empty square has no adjacent flowers, leave it empty.
+Otherwise replace it with the count of adjacent flowers.
+
+For example, you may receive a 5 x 4 board like this (empty spaces are represented here with the '·' character for display on screen):
+
+```text
+·*·*·
+··*··
+··*··
+·····
+```
+
+Which your code should transform into this:
+
+```text
+1*3*1
+13*31
+·2*2·
+·111·
+```
diff --git a/exercises/practice/flower-field/.docs/introduction.md b/exercises/practice/flower-field/.docs/introduction.md
new file mode 100644
index 000000000..af9b61536
--- /dev/null
+++ b/exercises/practice/flower-field/.docs/introduction.md
@@ -0,0 +1,7 @@
+# Introduction
+
+[Flower Field][history] is a compassionate reimagining of the popular game Minesweeper.
+The object of the game is to find all the flowers in the garden using numeric hints that indicate how many flowers are directly adjacent (horizontally, vertically, diagonally) to a square.
+"Flower Field" shipped in regional versions of Microsoft Windows in Italy, Germany, South Korea, Japan and Taiwan.
+
+[history]: https://web.archive.org/web/20020409051321fw_/http://rcm.usr.dsi.unimi.it/rcmweb/fnm/
diff --git a/exercises/practice/flower-field/.meta/config.json b/exercises/practice/flower-field/.meta/config.json
new file mode 100644
index 000000000..54dc83896
--- /dev/null
+++ b/exercises/practice/flower-field/.meta/config.json
@@ -0,0 +1,41 @@
+{
+ "authors": [
+ "stkent"
+ ],
+ "contributors": [
+ "aadityakulkarni",
+ "BNAndras",
+ "FridaTveit",
+ "hgvanpariya",
+ "jmrunkle",
+ "jsertel",
+ "kytrinyx",
+ "lemoncurry",
+ "matthewmorgan",
+ "matthewstyler",
+ "morrme",
+ "msomji",
+ "muzimuzhi",
+ "redshirt4",
+ "SleeplessByte",
+ "Smarticles101",
+ "sshine",
+ "vivshaw",
+ "Zaldrick"
+ ],
+ "files": {
+ "solution": [
+ "src/main/java/FlowerFieldBoard.java"
+ ],
+ "test": [
+ "src/test/java/FlowerFieldBoardTest.java"
+ ],
+ "example": [
+ ".meta/src/reference/java/FlowerFieldBoard.java"
+ ],
+ "invalidator": [
+ "build.gradle"
+ ]
+ },
+ "blurb": "Mark all the flowers in a garden."
+}
diff --git a/exercises/practice/flower-field/.meta/src/reference/java/FlowerFieldBoard.java b/exercises/practice/flower-field/.meta/src/reference/java/FlowerFieldBoard.java
new file mode 100644
index 000000000..0fa97e128
--- /dev/null
+++ b/exercises/practice/flower-field/.meta/src/reference/java/FlowerFieldBoard.java
@@ -0,0 +1,75 @@
+import java.util.ArrayList;
+import java.util.List;
+
+final class FlowerFieldBoard {
+
+ private static final char FLOWER_CHAR = '*';
+
+ private static final char SPACE_CHAR = ' ';
+
+ private final List rawRepresentation;
+
+ private final int numberOfRows;
+
+ private final int numberOfColumns;
+
+ FlowerFieldBoard(final List rawRepresentation) {
+ this.rawRepresentation = rawRepresentation;
+ this.numberOfRows = rawRepresentation.size();
+ this.numberOfColumns = rawRepresentation.isEmpty() ? 0 : rawRepresentation.get(0).length();
+ }
+
+ List withNumbers() {
+ final List result = new ArrayList<>();
+
+ for (int rowNumber = 0; rowNumber < numberOfRows; rowNumber++) {
+ result.add(getRowWithNumbers(rowNumber));
+ }
+
+ return result;
+ }
+
+ private String getRowWithNumbers(final int rowNumber) {
+ StringBuilder result = new StringBuilder(numberOfColumns);
+
+ for (int columnNumber = 0; columnNumber < numberOfColumns; columnNumber++) {
+ result.append(getCellNumber(rowNumber, columnNumber));
+ }
+
+ return result.toString();
+ }
+
+ private char getCellNumber(final int rowNumber, final int columnNumber) {
+ // If (rowNumber, columnNumber) is a flower, we're done.
+ if (rawRepresentation.get(rowNumber).charAt(columnNumber) == FLOWER_CHAR) {
+ return FLOWER_CHAR;
+ }
+
+ final int flowerCount = computeFlowerCountAround(rowNumber, columnNumber);
+
+ // If computed count is positive, add it to the annotated row. Otherwise, add a blank space.
+ return flowerCount > 0 ? Character.forDigit(flowerCount, 10) : SPACE_CHAR;
+ }
+
+ private int computeFlowerCountAround(final int rowNumber, final int columnNumber) {
+ int result = 0;
+
+ // Compute row and column ranges to inspect (respecting board edges).
+ final int minRowToInspect = Math.max(rowNumber - 1, 0);
+ final int maxRowToInspect = Math.min(rowNumber + 1, numberOfRows - 1);
+ final int minColToInspect = Math.max(columnNumber - 1, 0);
+ final int maxColToInspect = Math.min(columnNumber + 1, numberOfColumns - 1);
+
+ // Count flowers in the cells surrounding (row, col).
+ for (int rowToInspect = minRowToInspect; rowToInspect <= maxRowToInspect; rowToInspect++) {
+ for (int colToInspect = minColToInspect; colToInspect <= maxColToInspect; colToInspect++) {
+ if (rawRepresentation.get(rowToInspect).charAt(colToInspect) == FLOWER_CHAR) {
+ result += 1;
+ }
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/exercises/practice/flower-field/.meta/tests.toml b/exercises/practice/flower-field/.meta/tests.toml
new file mode 100644
index 000000000..965ba8fd4
--- /dev/null
+++ b/exercises/practice/flower-field/.meta/tests.toml
@@ -0,0 +1,49 @@
+# This is an auto-generated file.
+#
+# Regenerating this file via `configlet sync` will:
+# - Recreate every `description` key/value pair
+# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
+# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
+# - Preserve any other key/value pair
+#
+# As user-added comments (using the # character) will be removed when this file
+# is regenerated, comments can be added via a `comment` key.
+
+[237ff487-467a-47e1-9b01-8a891844f86c]
+description = "no rows"
+
+[4b4134ec-e20f-439c-a295-664c38950ba1]
+description = "no columns"
+
+[d774d054-bbad-4867-88ae-069cbd1c4f92]
+description = "no flowers"
+
+[225176a0-725e-43cd-aa13-9dced501f16e]
+description = "garden full of flowers"
+
+[3f345495-f1a5-4132-8411-74bd7ca08c49]
+description = "flower surrounded by spaces"
+
+[6cb04070-4199-4ef7-a6fa-92f68c660fca]
+description = "space surrounded by flowers"
+
+[272d2306-9f62-44fe-8ab5-6b0f43a26338]
+description = "horizontal line"
+
+[c6f0a4b2-58d0-4bf6-ad8d-ccf4144f1f8e]
+description = "horizontal line, flowers at edges"
+
+[a54e84b7-3b25-44a8-b8cf-1753c8bb4cf5]
+description = "vertical line"
+
+[b40f42f5-dec5-4abc-b167-3f08195189c1]
+description = "vertical line, flowers at edges"
+
+[58674965-7b42-4818-b930-0215062d543c]
+description = "cross"
+
+[dd9d4ca8-9e68-4f78-a677-a2a70fd7a7b8]
+description = "large garden"
+
+[6e4ac13a-3e43-4728-a2e3-3551d4b1a996]
+description = "multiple adjacent flowers"
diff --git a/exercises/practice/flower-field/build.gradle b/exercises/practice/flower-field/build.gradle
new file mode 100644
index 000000000..d28f35dee
--- /dev/null
+++ b/exercises/practice/flower-field/build.gradle
@@ -0,0 +1,25 @@
+plugins {
+ id "java"
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation platform("org.junit:junit-bom:5.10.0")
+ testImplementation "org.junit.jupiter:junit-jupiter"
+ testImplementation "org.assertj:assertj-core:3.25.1"
+
+ testRuntimeOnly "org.junit.platform:junit-platform-launcher"
+}
+
+test {
+ useJUnitPlatform()
+
+ testLogging {
+ exceptionFormat = "full"
+ showStandardStreams = true
+ events = ["passed", "failed", "skipped"]
+ }
+}
diff --git a/exercises/practice/flower-field/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/flower-field/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..f8e1ee312
Binary files /dev/null and b/exercises/practice/flower-field/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/flower-field/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/flower-field/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..4d97ea344
--- /dev/null
+++ b/exercises/practice/flower-field/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/exercises/practice/flower-field/gradlew b/exercises/practice/flower-field/gradlew
new file mode 100755
index 000000000..adff685a0
--- /dev/null
+++ b/exercises/practice/flower-field/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright © 2015 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/exercises/practice/flower-field/gradlew.bat b/exercises/practice/flower-field/gradlew.bat
new file mode 100644
index 000000000..c4bdd3ab8
--- /dev/null
+++ b/exercises/practice/flower-field/gradlew.bat
@@ -0,0 +1,93 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/exercises/practice/flower-field/src/main/java/FlowerFieldBoard.java b/exercises/practice/flower-field/src/main/java/FlowerFieldBoard.java
new file mode 100644
index 000000000..db059db34
--- /dev/null
+++ b/exercises/practice/flower-field/src/main/java/FlowerFieldBoard.java
@@ -0,0 +1,13 @@
+import java.util.List;
+
+class FlowerFieldBoard {
+
+ FlowerFieldBoard(List boardRows) {
+ throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
+ }
+
+ List withNumbers() {
+ throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
+ }
+
+}
\ No newline at end of file
diff --git a/exercises/practice/flower-field/src/test/java/FlowerFieldBoardTest.java b/exercises/practice/flower-field/src/test/java/FlowerFieldBoardTest.java
new file mode 100644
index 000000000..58f995293
--- /dev/null
+++ b/exercises/practice/flower-field/src/test/java/FlowerFieldBoardTest.java
@@ -0,0 +1,269 @@
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class FlowerFieldBoardTest {
+
+ @Test
+ @DisplayName("no rows")
+ public void testInputBoardWithNoRowsAndNoColumns() {
+ List inputBoard = Collections.emptyList();
+ List expectedNumberedBoard = Collections.emptyList();
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("no columns")
+ public void testInputBoardWithOneRowAndNoColumns() {
+ List inputBoard = List.of("");
+ List expectedNumberedBoard = List.of("");
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("no flowers")
+ public void testInputBoardWithNoFlowers() {
+ List inputBoard = List.of(
+ " ",
+ " ",
+ " "
+ );
+
+ List expectedNumberedBoard = List.of(
+ " ",
+ " ",
+ " "
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("garden full of flowers")
+ public void testInputBoardWithOnlyFlowers() {
+ List inputBoard = List.of(
+ "***",
+ "***",
+ "***"
+ );
+
+ List expectedNumberedBoard = List.of(
+ "***",
+ "***",
+ "***"
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("flower surrounded by spaces")
+ public void testInputBoardWithSingleFlowerAtCenter() {
+ List inputBoard = List.of(
+ " ",
+ " * ",
+ " "
+ );
+
+ List expectedNumberedBoard = List.of(
+ "111",
+ "1*1",
+ "111"
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("space surrounded by flowers")
+ public void testInputBoardWithFlowersAroundPerimeter() {
+ List inputBoard = List.of(
+ "***",
+ "* *",
+ "***"
+ );
+
+ List expectedNumberedBoard = List.of(
+ "***",
+ "*8*",
+ "***"
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("horizontal line")
+ public void testInputBoardWithSingleRowAndTwoFlowers() {
+ List inputBoard = List.of(
+ " * * "
+ );
+
+ List expectedNumberedBoard = List.of(
+ "1*2*1"
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("horizontal line, flowers at edges")
+ public void testInputBoardWithSingleRowAndTwoFlowersAtEdges() {
+ List inputBoard = List.of(
+ "* *"
+ );
+
+ List expectedNumberedBoard = List.of(
+ "*1 1*"
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("vertical line")
+ public void testInputBoardWithSingleColumnAndTwoFlowers() {
+ List inputBoard = List.of(
+ " ",
+ "*",
+ " ",
+ "*",
+ " "
+ );
+
+ List expectedNumberedBoard = List.of(
+ "1",
+ "*",
+ "2",
+ "*",
+ "1"
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("vertical line, flowers at edges")
+ public void testInputBoardWithSingleColumnAndTwoFlowersAtEdges() {
+ List inputBoard = List.of(
+ "*",
+ " ",
+ " ",
+ " ",
+ "*"
+ );
+
+ List expectedNumberedBoard = List.of(
+ "*",
+ "1",
+ " ",
+ "1",
+ "*"
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("cross")
+ public void testInputBoardWithFlowersInCross() {
+ List inputBoard = List.of(
+ " * ",
+ " * ",
+ "*****",
+ " * ",
+ " * "
+ );
+
+ List expectedNumberedBoard = List.of(
+ " 2*2 ",
+ "25*52",
+ "*****",
+ "25*52",
+ " 2*2 "
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("large garden")
+ public void testLargeInputBoard() {
+ List inputBoard = List.of(
+ " * * ",
+ " * ",
+ " * ",
+ " * *",
+ " * * ",
+ " "
+ );
+
+ List expectedNumberedBoard = List.of(
+ "1*22*1",
+ "12*322",
+ " 123*2",
+ "112*4*",
+ "1*22*2",
+ "111111"
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+
+ @Disabled("Remove to run test")
+ @Test
+ @DisplayName("multiple adjacent flowers")
+ public void testMultipleAdjacentFlowers() {
+ List inputBoard = List.of(
+ " ** "
+ );
+
+ List expectedNumberedBoard = List.of(
+ "1**1"
+ );
+
+ List actualNumberedBoard = new FlowerFieldBoard(inputBoard).withNumbers();
+
+ assertThat(actualNumberedBoard).isEqualTo(expectedNumberedBoard);
+ }
+}
diff --git a/exercises/practice/food-chain/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/food-chain/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/food-chain/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/food-chain/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/food-chain/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/food-chain/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/food-chain/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/food-chain/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/food-chain/gradlew b/exercises/practice/food-chain/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/food-chain/gradlew
+++ b/exercises/practice/food-chain/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/food-chain/gradlew.bat b/exercises/practice/food-chain/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/food-chain/gradlew.bat
+++ b/exercises/practice/food-chain/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/food-chain/src/test/java/FoodChainTest.java b/exercises/practice/food-chain/src/test/java/FoodChainTest.java
index a0f5caa57..43e7a0746 100644
--- a/exercises/practice/food-chain/src/test/java/FoodChainTest.java
+++ b/exercises/practice/food-chain/src/test/java/FoodChainTest.java
@@ -1,5 +1,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -13,6 +14,7 @@ public void setup() {
}
@Test
+ @DisplayName("fly")
public void fly() {
int verse = 1;
String expected = "I know an old lady who swallowed a fly.\n" +
@@ -23,6 +25,7 @@ public void fly() {
@Test
@Disabled("Remove to run test.")
+ @DisplayName("spider")
public void spider() {
int verse = 2;
String expected = "I know an old lady who swallowed a spider.\n" +
@@ -35,6 +38,7 @@ public void spider() {
@Test
@Disabled("Remove to run test.")
+ @DisplayName("bird")
public void bird() {
int verse = 3;
String expected = "I know an old lady who swallowed a bird.\n" +
@@ -49,6 +53,7 @@ public void bird() {
@Test
@Disabled("Remove to run test.")
+ @DisplayName("cat")
public void cat() {
int verse = 4;
String expected = "I know an old lady who swallowed a cat.\n" +
@@ -65,6 +70,7 @@ public void cat() {
@Test
@Disabled("Remove to run test.")
+ @DisplayName("dog")
public void dog() {
int verse = 5;
String expected = "I know an old lady who swallowed a dog.\n" +
@@ -81,6 +87,7 @@ public void dog() {
@Test
@Disabled("Remove to run test.")
+ @DisplayName("goat")
public void goat() {
int verse = 6;
String expected = "I know an old lady who swallowed a goat.\n" +
@@ -98,6 +105,7 @@ public void goat() {
@Test
@Disabled("Remove to run test.")
+ @DisplayName("cow")
public void cow() {
int verse = 7;
String expected = "I know an old lady who swallowed a cow.\n" +
@@ -116,6 +124,7 @@ public void cow() {
@Test
@Disabled("Remove to run test.")
+ @DisplayName("horse")
public void horse() {
int verse = 8;
String expected = "I know an old lady who swallowed a horse.\n" +
@@ -127,6 +136,7 @@ public void horse() {
@Test
@Disabled("Remove to run test.")
+ @DisplayName("multiple verses")
public void multipleVerses() {
int startVerse = 1;
int endVerse = 3;
@@ -151,6 +161,7 @@ public void multipleVerses() {
@Test
@Disabled("Remove to run test.")
+ @DisplayName("full song")
public void wholeSong() {
int startVerse = 1;
int endVerse = 8;
diff --git a/exercises/practice/forth/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/forth/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/forth/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/forth/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/forth/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/forth/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/forth/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/forth/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/forth/gradlew b/exercises/practice/forth/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/forth/gradlew
+++ b/exercises/practice/forth/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/forth/gradlew.bat b/exercises/practice/forth/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/forth/gradlew.bat
+++ b/exercises/practice/forth/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/forth/src/test/java/ForthEvaluatorTest.java b/exercises/practice/forth/src/test/java/ForthEvaluatorTest.java
index bd36657b3..9a7c23e01 100644
--- a/exercises/practice/forth/src/test/java/ForthEvaluatorTest.java
+++ b/exercises/practice/forth/src/test/java/ForthEvaluatorTest.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.Arrays;
@@ -13,6 +14,7 @@ public class ForthEvaluatorTest {
private ForthEvaluator forthEvaluator = new ForthEvaluator();
@Test
+ @DisplayName("numbers just get pushed onto the stack")
public void testNumbersAreJustPushedOntoTheStack() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 3 4 5")))
.containsExactly(1, 2, 3, 4, 5);
@@ -20,6 +22,7 @@ public void testNumbersAreJustPushedOntoTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("pushes negative numbers onto the stack")
public void testNegativeNumbersArePushedOntoTheStack() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("-1 -2 -3 -4 -5")))
.containsExactly(-1, -2, -3, -4, -5);
@@ -27,6 +30,7 @@ public void testNegativeNumbersArePushedOntoTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can add two numbers")
public void testTwoNumbersCanBeAdded() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 +")))
.containsExactly(3);
@@ -34,6 +38,7 @@ public void testTwoNumbersCanBeAdded() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is nothing on the stack")
public void testErrorIfAdditionAttemptedWithNothingOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("+")))
@@ -42,6 +47,7 @@ public void testErrorIfAdditionAttemptedWithNothingOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is only one value on the stack")
public void testErrorIfAdditionAttemptedWithOneNumberOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("1 +")))
@@ -50,6 +56,7 @@ public void testErrorIfAdditionAttemptedWithOneNumberOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("more than two values on the stack")
public void testAdditionForMoreThanTwoValuesOnTheStack() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 3 +")))
.containsExactly(1, 5);
@@ -57,6 +64,7 @@ public void testAdditionForMoreThanTwoValuesOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can subtract two numbers")
public void testTwoNumbersCanBeSubtracted() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("3 4 -")))
.containsExactly(-1);
@@ -64,6 +72,7 @@ public void testTwoNumbersCanBeSubtracted() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is nothing on the stack")
public void testErrorIfSubtractionAttemptedWithNothingOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("-")))
@@ -73,6 +82,7 @@ public void testErrorIfSubtractionAttemptedWithNothingOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is only one value on the stack")
public void testErrorIfSubtractionAttemptedWithOneNumberOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("1 -")))
@@ -81,6 +91,7 @@ public void testErrorIfSubtractionAttemptedWithOneNumberOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("more than two values on the stack")
public void testSubtractionForMoreThanTwoValuesOnTheStack() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 12 3 -")))
.containsExactly(1, 9);
@@ -88,12 +99,14 @@ public void testSubtractionForMoreThanTwoValuesOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can multiply two numbers")
public void testTwoNumbersCanBeMultiplied() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("2 4 *"))).containsExactly(8);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is nothing on the stack")
public void testErrorIfMultiplicationAttemptedWithNothingOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("*")))
@@ -102,6 +115,7 @@ public void testErrorIfMultiplicationAttemptedWithNothingOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is only one value on the stack")
public void testErrorIfMultiplicationAttemptedWithOneNumberOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("1 *")))
@@ -110,6 +124,7 @@ public void testErrorIfMultiplicationAttemptedWithOneNumberOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("more than two values on the stack")
public void testMultiplicationForMoreThanTwoValuesOnTheStack() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 3 *")))
.containsExactly(1, 6);
@@ -117,18 +132,21 @@ public void testMultiplicationForMoreThanTwoValuesOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can divide two numbers")
public void testTwoNumbersCanBeDivided() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("12 3 /"))).containsExactly(4);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("performs integer division")
public void testThatIntegerDivisionIsUsed() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("8 3 /"))).containsExactly(2);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if dividing by zero")
public void testErrorIfDividingByZero() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("4 0 /")))
@@ -137,6 +155,7 @@ public void testErrorIfDividingByZero() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is nothing on the stack")
public void testErrorIfDivisionAttemptedWithNothingOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("/")))
@@ -145,6 +164,7 @@ public void testErrorIfDivisionAttemptedWithNothingOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is only one value on the stack")
public void testErrorIfDivisionAttemptedWithOneNumberOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("1 /")))
@@ -153,6 +173,7 @@ public void testErrorIfDivisionAttemptedWithOneNumberOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("more than two values on the stack")
public void testDivisionForMoreThanTwoValuesOnTheStack() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 12 3 /")))
.containsExactly(1, 4);
@@ -160,42 +181,49 @@ public void testDivisionForMoreThanTwoValuesOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("addition and subtraction")
public void testCombinedAdditionAndSubtraction() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 + 4 -"))).containsExactly(-1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("multiplication and division")
public void testCombinedMultiplicationAndDivision() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("2 4 * 3 /"))).containsExactly(2);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("multiplication and addition")
public void testCombinedMultiplicationAndAddition() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 3 4 * +"))).containsExactly(13);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("addition and multiplication")
public void testCombinedAdditionAndMultiplication() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 3 4 + *"))).containsExactly(7);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("copies a value on the stack")
public void testDupCopiesAValueOnTheStack() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 dup"))).containsExactly(1, 1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("copies the top value on the stack")
public void testDupCopiesTopValueOnTheStack() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 dup"))).containsExactly(1, 2, 2);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is nothing on the stack")
public void testErrorIfDuplicatingAttemptedWithNothingOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("dup")))
@@ -204,18 +232,21 @@ public void testErrorIfDuplicatingAttemptedWithNothingOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("removes the top value on the stack if it is the only one")
public void testDropRemovesTheTopValueOnTheStackIfItIsTheOnlyOne() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 drop"))).isEmpty();
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("removes the top value on the stack if it is not the only one")
public void testDropRemovesTheTopValueOnTheStackIfItIsNotTheOnlyOne() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 drop"))).containsExactly(1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is nothing on the stack")
public void testErrorIfDroppingAttemptedWithNothingOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("drop")))
@@ -224,12 +255,14 @@ public void testErrorIfDroppingAttemptedWithNothingOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("swaps the top two values on the stack if they are the only ones")
public void testSwapSwapsTheTopTwosValueOnTheStackIfTheyAreTheOnlyOnes() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 swap"))).containsExactly(2, 1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("swaps the top two values on the stack if they are not the only ones")
public void testSwapSwapsTheTopTwosValueOnTheStackIfTheyAreNotTheOnlyOnes() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 3 swap")))
.containsExactly(1, 3, 2);
@@ -237,6 +270,7 @@ public void testSwapSwapsTheTopTwosValueOnTheStackIfTheyAreNotTheOnlyOnes() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is nothing on the stack")
public void testErrorIfSwappingAttemptedWithNothingOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("swap")))
@@ -245,6 +279,7 @@ public void testErrorIfSwappingAttemptedWithNothingOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is only one value on the stack")
public void testErrorIfSwappingAttemptedWithOneNumberOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("1 swap")))
@@ -253,6 +288,7 @@ public void testErrorIfSwappingAttemptedWithOneNumberOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("copies the second element if there are only two")
public void testOverCopiesTheSecondElementIfThereAreOnlyTwo() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 over")))
.containsExactly(1, 2, 1);
@@ -260,6 +296,7 @@ public void testOverCopiesTheSecondElementIfThereAreOnlyTwo() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("copies the second element if there are more than two")
public void testOverCopiesTheSecondElementIfThereAreMoreThanTwo() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 3 over")))
.containsExactly(1, 2, 3, 2);
@@ -267,6 +304,7 @@ public void testOverCopiesTheSecondElementIfThereAreMoreThanTwo() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is nothing on the stack")
public void testErrorIfOveringAttemptedWithNothingOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("over")))
@@ -275,6 +313,7 @@ public void testErrorIfOveringAttemptedWithNothingOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if there is only one value on the stack")
public void testErrorIfOveringAttemptedWithOneNumberOnTheStack() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("1 over")))
@@ -283,6 +322,7 @@ public void testErrorIfOveringAttemptedWithOneNumberOnTheStack() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can consist of built-in words")
public void testUserDefinedOperatorsCanConsistOfBuiltInOperators() {
assertThat(forthEvaluator.evaluateProgram(Arrays.asList(": dup-twice dup dup ;", "1 dup-twice")))
.containsExactly(1, 1, 1);
@@ -290,6 +330,7 @@ public void testUserDefinedOperatorsCanConsistOfBuiltInOperators() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("execute in the right order")
public void testUserDefinedOperatorsAreEvaluatedInTheCorrectOrder() {
assertThat(forthEvaluator.evaluateProgram(Arrays.asList(": countup 1 2 3 ;", "countup")))
.containsExactly(1, 2, 3);
@@ -297,6 +338,7 @@ public void testUserDefinedOperatorsAreEvaluatedInTheCorrectOrder() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can override other user-defined words")
public void testCanRedefineAUserDefinedOperator() {
assertThat(forthEvaluator.evaluateProgram(Arrays.asList(": foo dup ;", ": foo dup dup ;", "1 foo")))
.containsExactly(1, 1, 1);
@@ -304,6 +346,7 @@ public void testCanRedefineAUserDefinedOperator() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can override built-in words")
public void testCanOverrideBuiltInWordOperators() {
assertThat(forthEvaluator.evaluateProgram(Arrays.asList(": swap dup ;", "1 swap")))
.containsExactly(1, 1);
@@ -311,6 +354,7 @@ public void testCanOverrideBuiltInWordOperators() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can override built-in operators")
public void testCanOverrideBuiltInArithmeticOperators() {
assertThat(forthEvaluator.evaluateProgram(Arrays.asList(": + * ;", "3 4 +")))
.containsExactly(12);
@@ -318,6 +362,7 @@ public void testCanOverrideBuiltInArithmeticOperators() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can use different words with the same name")
public void testCanUseDifferentWordsWithTheSameName() {
assertThat(forthEvaluator.evaluateProgram(Arrays.asList(": foo 5 ;", ": bar foo ;", ": foo 6 ;", "bar foo")))
.containsExactly(5, 6);
@@ -325,6 +370,7 @@ public void testCanUseDifferentWordsWithTheSameName() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("can define word that uses word with the same name")
public void testCanDefineWordThatUsesWordWithTheSameName() {
assertThat(forthEvaluator.evaluateProgram(Arrays.asList(": foo 10 ;", ": foo foo 1 + ;", "foo")))
.containsExactly(11);
@@ -332,6 +378,7 @@ public void testCanDefineWordThatUsesWordWithTheSameName() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("cannot redefine non-negative numbers")
public void testCannotRedefineNonNegativeNumbers() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList(": 1 2 ;")))
@@ -340,6 +387,7 @@ public void testCannotRedefineNonNegativeNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("cannot redefine negative numbers")
public void testCannotRedefineNegativeNumbers() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList(": -1 2 ;")))
@@ -348,6 +396,7 @@ public void testCannotRedefineNegativeNumbers() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("errors if executing a non-existent word")
public void testErrorIfEvaluatingAnUndefinedOperator() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> forthEvaluator.evaluateProgram(Collections.singletonList("foo")))
@@ -356,6 +405,7 @@ public void testErrorIfEvaluatingAnUndefinedOperator() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("DUP is case-insensitive")
public void testDupIsCaseInsensitive() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 DUP Dup dup")))
.containsExactly(1, 1, 1, 1);
@@ -363,6 +413,7 @@ public void testDupIsCaseInsensitive() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("DROP is case-insensitive")
public void testDropIsCaseInsensitive() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 3 4 DROP Drop drop")))
.containsExactly(1);
@@ -370,6 +421,7 @@ public void testDropIsCaseInsensitive() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("SWAP is case-insensitive")
public void testSwapIsCaseInsensitive() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 SWAP 3 Swap 4 swap")))
.containsExactly(2, 3, 4, 1);
@@ -377,6 +429,7 @@ public void testSwapIsCaseInsensitive() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("OVER is case-insensitive")
public void testOverIsCaseInsensitive() {
assertThat(forthEvaluator.evaluateProgram(Collections.singletonList("1 2 OVER Over over")))
.containsExactly(1, 2, 1, 2, 1);
@@ -384,6 +437,7 @@ public void testOverIsCaseInsensitive() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("user-defined words are case-insensitive")
public void testUserDefinedWordsAreCaseInsensitive() {
assertThat(forthEvaluator.evaluateProgram(Arrays.asList(": foo dup ;", "1 FOO Foo foo")))
.containsExactly(1, 1, 1, 1);
@@ -391,6 +445,7 @@ public void testUserDefinedWordsAreCaseInsensitive() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("definitions are case-insensitive")
public void testDefinitionsAreCaseInsensitive() {
assertThat(forthEvaluator.evaluateProgram(Arrays.asList(": SWAP DUP Dup dup ;", "1 swap")))
.containsExactly(1, 1, 1, 1);
@@ -398,6 +453,7 @@ public void testDefinitionsAreCaseInsensitive() {
@Disabled
@Test
+ @DisplayName("only defines locally")
public void testDefinitionsAreOnlyDefinedLocally() {
ForthEvaluator firstInstance = new ForthEvaluator();
ForthEvaluator secondInstance = new ForthEvaluator();
diff --git a/exercises/practice/game-of-life/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/game-of-life/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/game-of-life/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/game-of-life/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/game-of-life/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/game-of-life/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/game-of-life/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/game-of-life/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/game-of-life/gradlew b/exercises/practice/game-of-life/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/game-of-life/gradlew
+++ b/exercises/practice/game-of-life/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/game-of-life/gradlew.bat b/exercises/practice/game-of-life/gradlew.bat
index 93e3f59f1..c4bdd3ab8 100644
--- a/exercises/practice/game-of-life/gradlew.bat
+++ b/exercises/practice/game-of-life/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/gigasecond/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/gigasecond/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/gigasecond/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/gigasecond/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/gigasecond/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/gigasecond/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/gigasecond/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/gigasecond/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/gigasecond/gradlew b/exercises/practice/gigasecond/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/gigasecond/gradlew
+++ b/exercises/practice/gigasecond/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/gigasecond/gradlew.bat b/exercises/practice/gigasecond/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/gigasecond/gradlew.bat
+++ b/exercises/practice/gigasecond/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/gigasecond/src/test/java/GigasecondTest.java b/exercises/practice/gigasecond/src/test/java/GigasecondTest.java
index 6b190f606..2f5872fdd 100644
--- a/exercises/practice/gigasecond/src/test/java/GigasecondTest.java
+++ b/exercises/practice/gigasecond/src/test/java/GigasecondTest.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.time.LocalDate;
@@ -10,6 +11,7 @@
public class GigasecondTest {
@Test
+ @DisplayName("date only specification of time")
public void modernTime() {
Gigasecond gigaSecond = new Gigasecond(LocalDate.of(2011, Month.APRIL, 25));
@@ -18,6 +20,7 @@ public void modernTime() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("second test for date only specification of time")
public void afterEpochTime() {
Gigasecond gigaSecond = new Gigasecond(LocalDate.of(1977, Month.JUNE, 13));
@@ -26,6 +29,7 @@ public void afterEpochTime() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("third test for date only specification of time")
public void beforeEpochTime() {
Gigasecond gigaSecond = new Gigasecond(LocalDate.of(1959, Month.JULY, 19));
@@ -34,6 +38,7 @@ public void beforeEpochTime() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("full time specified")
public void withFullTimeSpecified() {
Gigasecond gigaSecond = new Gigasecond(LocalDateTime.of(2015, Month.JANUARY, 24, 22, 0, 0));
@@ -42,6 +47,7 @@ public void withFullTimeSpecified() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("full time with day roll-over")
public void withFullTimeSpecifiedAndDayRollover() {
Gigasecond gigaSecond = new Gigasecond(LocalDateTime.of(2015, Month.JANUARY, 24, 23, 59, 59));
@@ -50,6 +56,7 @@ public void withFullTimeSpecifiedAndDayRollover() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("does not mutate the input")
public void doesNotMutateInput() {
LocalDateTime input = LocalDateTime.of(2015, Month.JANUARY, 24, 23, 59, 59);
new Gigasecond(input).getDateTime();
diff --git a/exercises/practice/go-counting/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/go-counting/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/go-counting/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/go-counting/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/go-counting/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/go-counting/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/go-counting/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/go-counting/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/go-counting/gradlew b/exercises/practice/go-counting/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/go-counting/gradlew
+++ b/exercises/practice/go-counting/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/go-counting/gradlew.bat b/exercises/practice/go-counting/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/go-counting/gradlew.bat
+++ b/exercises/practice/go-counting/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/go-counting/src/test/java/GoCountingTest.java b/exercises/practice/go-counting/src/test/java/GoCountingTest.java
index 48e14dc78..2b336088c 100644
--- a/exercises/practice/go-counting/src/test/java/GoCountingTest.java
+++ b/exercises/practice/go-counting/src/test/java/GoCountingTest.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.awt.*;
@@ -18,6 +19,7 @@ public class GoCountingTest {
" W ";
@Test
+ @DisplayName("Black corner territory on 5x5 board")
public void blackCorner5x5BoardTest() {
GoCounting gocounting = new GoCounting(board5x5);
@@ -32,6 +34,7 @@ public void blackCorner5x5BoardTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("White center territory on 5x5 board")
public void whiteCenter5x5BoardTest() {
GoCounting gocounting = new GoCounting(board5x5);
@@ -44,6 +47,7 @@ public void whiteCenter5x5BoardTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Open corner territory on 5x5 board")
public void openCorner5x5BoardTest() {
GoCounting gocounting = new GoCounting(board5x5);
@@ -58,6 +62,7 @@ public void openCorner5x5BoardTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("A stone and not a territory on 5x5 board")
public void stoneNotTerritory5x5Board() {
GoCounting gocounting = new GoCounting(board5x5);
@@ -69,6 +74,7 @@ public void stoneNotTerritory5x5Board() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Invalid because X is too low for 5x5 board")
public void invalidXTooLow5x5Board() {
GoCounting gocounting = new GoCounting(board5x5);
@@ -79,6 +85,7 @@ public void invalidXTooLow5x5Board() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Invalid because X is too high for 5x5 board")
public void invalidXTooHigh5x5Board() {
GoCounting gocounting = new GoCounting(board5x5);
@@ -89,6 +96,7 @@ public void invalidXTooHigh5x5Board() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Invalid because Y is too low for 5x5 board")
public void invalidYTooLow5x5Board() {
GoCounting gocounting = new GoCounting(board5x5);
@@ -99,6 +107,7 @@ public void invalidYTooLow5x5Board() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Invalid because Y is too high for 5x5 board")
public void invalidYTooHigh5x5Board() {
GoCounting gocounting = new GoCounting(board5x5);
@@ -109,6 +118,7 @@ public void invalidYTooHigh5x5Board() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One territory is the whole board")
public void oneTerritoryIsWholeBoardTest() {
GoCounting gocounting = new GoCounting(" ");
@@ -127,6 +137,7 @@ public void oneTerritoryIsWholeBoardTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Two territory rectangular board")
public void twoTerritoryRectangularBoardTest() {
GoCounting gocounting = new GoCounting(" BW \n BW ");
@@ -150,6 +161,7 @@ public void twoTerritoryRectangularBoardTest() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Two region rectangular board")
public void twoRegionRectangularBoardTest() {
GoCounting gocounting = new GoCounting(" B ");
diff --git a/exercises/practice/grade-school/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/grade-school/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/grade-school/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/grade-school/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/grade-school/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/grade-school/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/grade-school/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/grade-school/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/grade-school/gradlew b/exercises/practice/grade-school/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/grade-school/gradlew
+++ b/exercises/practice/grade-school/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/grade-school/gradlew.bat b/exercises/practice/grade-school/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/grade-school/gradlew.bat
+++ b/exercises/practice/grade-school/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/grade-school/src/test/java/SchoolTest.java b/exercises/practice/grade-school/src/test/java/SchoolTest.java
index 6363b8bd8..10a7fd728 100644
--- a/exercises/practice/grade-school/src/test/java/SchoolTest.java
+++ b/exercises/practice/grade-school/src/test/java/SchoolTest.java
@@ -1,5 +1,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -13,18 +14,21 @@ public void setUp() {
}
@Test
+ @DisplayName("Roster is empty when no student is added")
public void rosterReturnsAnEmptyListIfThereAreNoStudentsEnrolled() {
assertThat(school.roster()).isEmpty();
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Add a student")
public void addAStudent() {
assertThat(school.add("Aimee", 2)).isTrue();
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Student is added to the roster")
public void addingAStudentAddsThemToTheSortedRoster() {
school.add("Aimee", 2);
@@ -33,6 +37,7 @@ public void addingAStudentAddsThemToTheSortedRoster() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Adding multiple students in the same grade in the roster")
public void addingMultipleStudentsInTheSameGrade() {
assertThat(school.add("Blair", 2)).isTrue();
assertThat(school.add("James", 2)).isTrue();
@@ -41,6 +46,7 @@ public void addingMultipleStudentsInTheSameGrade() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple students in the same grade are added to the roster")
public void addingMoreStudentsAddsThemToTheSameSortedRoster() {
school.add("Blair", 2);
school.add("James", 2);
@@ -51,6 +57,7 @@ public void addingMoreStudentsAddsThemToTheSameSortedRoster() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot add student to same grade in the roster more than once")
public void cannotAddStudentsToSameGradeInTheRosterMoreThanOnce() {
assertThat(school.add("Blair", 2)).isTrue();
assertThat(school.add("James", 2)).isTrue();
@@ -60,6 +67,7 @@ public void cannotAddStudentsToSameGradeInTheRosterMoreThanOnce() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Student not added to same grade in the roster more than once")
public void studentNotAddedToSameGradeInTheRosterMoreThanOnce() {
school.add("Blair", 2);
school.add("James", 2);
@@ -71,6 +79,7 @@ public void studentNotAddedToSameGradeInTheRosterMoreThanOnce() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Adding students in multiple grades")
public void addingStudentsInMultipleGrades() {
assertThat(school.add("Chelsea", 3)).isTrue();
assertThat(school.add("Logan", 7)).isTrue();
@@ -78,6 +87,7 @@ public void addingStudentsInMultipleGrades() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Students in multiple grades are added to the roster")
public void addingStudentsToDifferentGradesAddsThemToTheSameSortedRoster() {
school.add("Chelsea", 3);
school.add("Logan", 7);
@@ -87,6 +97,7 @@ public void addingStudentsToDifferentGradesAddsThemToTheSameSortedRoster() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Cannot add same student to multiple grades in the roster")
public void cannotAddSameStudentToMultipleGradesInTheRoster() {
assertThat(school.add("Blair", 2)).isTrue();
assertThat(school.add("James", 2)).isTrue();
@@ -96,6 +107,7 @@ public void cannotAddSameStudentToMultipleGradesInTheRoster() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Student not added to multiple grades in the roster")
public void studentNotAddedToMultipleGradesInTheRoster() {
school.add("Blair", 2);
school.add("James", 2);
@@ -107,6 +119,7 @@ public void studentNotAddedToMultipleGradesInTheRoster() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Students are sorted by grades in the roster")
public void studentsAreSortedByGradeInTheRoster() {
school.add("Jim", 3);
school.add("Peter", 2);
@@ -117,6 +130,7 @@ public void studentsAreSortedByGradeInTheRoster() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Students are sorted by name in the roster")
public void studentsAreSortedByNameInTheRoster() {
school.add("Peter", 2);
school.add("Zoe", 2);
@@ -127,6 +141,7 @@ public void studentsAreSortedByNameInTheRoster() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Students are sorted by grades and then by name in the roster")
public void studentsAreSortedByGradeAndThenByNameInTheRoster() {
school.add("Peter", 2);
school.add("Anna", 1);
@@ -141,12 +156,14 @@ public void studentsAreSortedByGradeAndThenByNameInTheRoster() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Grade is empty if no students in the roster")
public void gradeIsEmptyIfNoStudentsInTheRoster() {
assertThat(school.grade(1)).isEmpty();
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("Grade is empty if no students in that grade")
public void gradeIsEmptyIfNoStudentsInThatGrade() {
school.add("Peter", 2);
school.add("Zoe", 2);
@@ -158,6 +175,7 @@ public void gradeIsEmptyIfNoStudentsInThatGrade() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Student not added to same grade more than once")
public void studentNotAddedToTheSameGradeMoreThanOnce() {
school.add("Blair", 2);
school.add("James", 2);
@@ -169,6 +187,7 @@ public void studentNotAddedToTheSameGradeMoreThanOnce() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Student not added to multiple grades")
public void studentNotAddedToMultipleGrades() {
school.add("Blair", 2);
school.add("James", 2);
@@ -181,6 +200,7 @@ public void studentNotAddedToMultipleGrades() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Students are sorted by name in a grade")
public void studentsAreSortedByNameInAGrade() {
school.add("Franklin", 5);
school.add("Bradley", 5);
diff --git a/exercises/practice/grains/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/grains/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/grains/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/grains/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/grains/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/grains/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/grains/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/grains/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/grains/gradlew b/exercises/practice/grains/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/grains/gradlew
+++ b/exercises/practice/grains/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/grains/gradlew.bat b/exercises/practice/grains/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/grains/gradlew.bat
+++ b/exercises/practice/grains/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/grains/src/test/java/GrainsTest.java b/exercises/practice/grains/src/test/java/GrainsTest.java
index 2b5a47689..a09e48e88 100644
--- a/exercises/practice/grains/src/test/java/GrainsTest.java
+++ b/exercises/practice/grains/src/test/java/GrainsTest.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.math.BigInteger;
@@ -11,6 +12,7 @@ public class GrainsTest {
private Grains grains = new Grains();
@Test
+ @DisplayName("returns the number of grains on the square")
public void countAtSquare1() {
BigInteger result = grains.grainsOnSquare(1);
assertThat(result).isEqualTo(new BigInteger("1"));
@@ -18,6 +20,7 @@ public void countAtSquare1() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("grains on square 2")
public void countAtSquare2() {
BigInteger result = grains.grainsOnSquare(2);
assertThat(result).isEqualTo(new BigInteger("2"));
@@ -25,6 +28,7 @@ public void countAtSquare2() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("grains on square 3")
public void countAtSquare3() {
BigInteger result = grains.grainsOnSquare(3);
assertThat(result).isEqualTo(new BigInteger("4"));
@@ -32,6 +36,7 @@ public void countAtSquare3() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("grains on square 4")
public void countAtSquare4() {
BigInteger result = grains.grainsOnSquare(4);
assertThat(result).isEqualTo(new BigInteger("8"));
@@ -39,6 +44,7 @@ public void countAtSquare4() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("grains on square 16")
public void countAtSquare16() {
BigInteger result = grains.grainsOnSquare(16);
assertThat(result).isEqualTo(new BigInteger("32768"));
@@ -46,6 +52,7 @@ public void countAtSquare16() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("grains on square 32")
public void countAtSquare32() {
BigInteger result = grains.grainsOnSquare(32);
assertThat(result).isEqualTo(new BigInteger("2147483648"));
@@ -53,6 +60,7 @@ public void countAtSquare32() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("grains on square 64")
public void countAtSquare64() {
BigInteger result = grains.grainsOnSquare(64);
assertThat(result).isEqualTo(new BigInteger("9223372036854775808"));
@@ -60,6 +68,7 @@ public void countAtSquare64() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("square 0 is invalid")
public void errorOnNullBoardSize() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> grains.grainsOnSquare(0))
@@ -68,6 +77,7 @@ public void errorOnNullBoardSize() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("negative square is invalid")
public void errorOnNegativeBoardSize() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> grains.grainsOnSquare(-1))
@@ -76,6 +86,7 @@ public void errorOnNegativeBoardSize() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("square greater than 64 is invalid")
public void errorOnExcessiveBoardSize() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> grains.grainsOnSquare(65))
@@ -84,6 +95,7 @@ public void errorOnExcessiveBoardSize() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("returns the total number of grains on the board")
public void totalNumberOfGrainsOnABoard() {
BigInteger total = grains.grainsOnBoard();
assertThat(total).isEqualTo(new BigInteger("18446744073709551615"));
diff --git a/exercises/practice/grep/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/grep/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/grep/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/grep/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/grep/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/grep/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/grep/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/grep/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/grep/gradlew b/exercises/practice/grep/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/grep/gradlew
+++ b/exercises/practice/grep/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/grep/gradlew.bat b/exercises/practice/grep/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/grep/gradlew.bat
+++ b/exercises/practice/grep/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/grep/src/test/java/GrepToolTest.java b/exercises/practice/grep/src/test/java/GrepToolTest.java
index 54c194ca2..d6d27816d 100644
--- a/exercises/practice/grep/src/test/java/GrepToolTest.java
+++ b/exercises/practice/grep/src/test/java/GrepToolTest.java
@@ -1,6 +1,7 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.IOException;
@@ -66,6 +67,7 @@ public void tearDown() throws IOException {
}
@Test
+ @DisplayName("One file, one match, no flags")
public void oneFileOneMatchNoFlags() {
String expected = "Of Atreus, Agamemnon, King of men.";
@@ -80,6 +82,7 @@ public void oneFileOneMatchNoFlags() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, one match, print line numbers flag")
public void oneFileOneMatchPrintLineNumbersFlag() {
String expected = "2:Of that Forbidden Tree, whose mortal tast";
@@ -94,6 +97,7 @@ public void oneFileOneMatchPrintLineNumbersFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, one match, case-insensitive flag")
public void oneFileOneMatchCaseInsensitiveFlag() {
String expected = "Of that Forbidden Tree, whose mortal tast";
@@ -108,6 +112,7 @@ public void oneFileOneMatchCaseInsensitiveFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, one match, print file names flag")
public void oneFileOneMatchPrintFileNamesFlag() {
String expected = "paradise-lost.txt";
@@ -122,6 +127,7 @@ public void oneFileOneMatchPrintFileNamesFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, one match, match entire lines flag")
public void oneFileOneMatchEntireLinesFlag() {
String expected = "With loss of Eden, till one greater Man";
@@ -136,6 +142,7 @@ public void oneFileOneMatchEntireLinesFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, one match, multiple flags")
public void oneFileOneMatchMultipleFlags() {
String expected = "9:Of Atreus, Agamemnon, King of men.";
@@ -150,6 +157,7 @@ public void oneFileOneMatchMultipleFlags() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, several matches, no flags")
public void oneFileSeveralMatchesNoFlags() {
String expected = "Nor how it may concern my modesty,\n"
+ "But I beseech your grace that I may know\n"
@@ -166,6 +174,7 @@ public void oneFileSeveralMatchesNoFlags() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, several matches, print line numbers flag")
public void oneFileSeveralMatchesPrintLineNumbersFlag() {
String expected = "3:Nor how it may concern my modesty,\n"
+ "5:But I beseech your grace that I may know\n"
@@ -182,6 +191,7 @@ public void oneFileSeveralMatchesPrintLineNumbersFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, several matches, match entire lines flag")
public void oneFileSeveralMatchesMatchEntireLineFlag() {
String expected = "";
@@ -196,6 +206,7 @@ public void oneFileSeveralMatchesMatchEntireLineFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, several matches, case-insensitive flag")
public void oneFileSeveralMatchesCaseInsensitiveFlag() {
String expected = "Achilles sing, O Goddess! Peleus' son;\n"
+ "The noble Chief Achilles from the son";
@@ -211,6 +222,7 @@ public void oneFileSeveralMatchesCaseInsensitiveFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, several matches, inverted flag")
public void oneFileSeveralMatchesInvertedFlag() {
String expected = "Brought Death into the World, and all our woe,\n"
+ "With loss of Eden, till one greater Man\n"
@@ -229,6 +241,7 @@ public void oneFileSeveralMatchesInvertedFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, no matches, various flags")
public void oneFileNoMatchesVariousFlags() {
String expected = "";
@@ -243,6 +256,7 @@ public void oneFileNoMatchesVariousFlags() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, one match, file flag takes precedence over line flag")
public void oneFileOneMatchFileFlagTakesPrecedenceOverLineFlag() {
String expected = "iliad.txt";
@@ -257,6 +271,7 @@ public void oneFileOneMatchFileFlagTakesPrecedenceOverLineFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("One file, several matches, inverted and match entire lines flags")
public void oneFileSeveralMatchesInvertedAndMatchEntireLinesFlags() {
String expected = "Achilles sing, O Goddess! Peleus' son;\n"
+ "His wrath pernicious, who ten thousand woes\n"
@@ -278,6 +293,7 @@ public void oneFileSeveralMatchesInvertedAndMatchEntireLinesFlags() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, one match, no flags")
public void multipleFilesOneMatchNoFlags() {
String expected = "iliad.txt:Of Atreus, Agamemnon, King of men.";
@@ -292,6 +308,7 @@ public void multipleFilesOneMatchNoFlags() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, several matches, no flags")
public void multipleFilesSeveralMatchesNoFlags() {
String expected = "midsummer-night.txt:Nor how it may concern my modesty,\n"
+ "midsummer-night.txt:But I beseech your grace that I may know\n"
@@ -308,6 +325,7 @@ public void multipleFilesSeveralMatchesNoFlags() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, several matches, print line numbers flag")
public void multipleFilesSeveralMatchesPrintLineNumbersFlag() {
String expected = "midsummer-night.txt:5:But I beseech your grace that I may know\n"
+ "midsummer-night.txt:6:The worst that may befall me in this case,\n"
@@ -325,6 +343,7 @@ public void multipleFilesSeveralMatchesPrintLineNumbersFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, one match, print file names flag")
public void multipleFilesOneMatchPrintFileNamesFlag() {
String expected = "iliad.txt\n"
+ "paradise-lost.txt";
@@ -340,6 +359,7 @@ public void multipleFilesOneMatchPrintFileNamesFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, several matches, case-insensitive flag")
public void multipleFilesSeveralMatchesCaseInsensitiveFlag() {
String expected = "iliad.txt:Caused to Achaia's host, sent many a soul\n"
+ "iliad.txt:Illustrious into Ades premature,\n"
@@ -363,6 +383,7 @@ public void multipleFilesSeveralMatchesCaseInsensitiveFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, several matches, inverted flag")
public void multipleFilesSeveralMatchesInvertedFlag() {
String expected = "iliad.txt:Achilles sing, O Goddess! Peleus' son;\n"
+ "iliad.txt:The noble Chief Achilles from the son\n"
@@ -379,6 +400,7 @@ public void multipleFilesSeveralMatchesInvertedFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, one match, match entire lines flag")
public void multipleFilesOneMatchEntireLinesFlag() {
String expected = "midsummer-night.txt:But I beseech your grace that I may know";
@@ -393,6 +415,7 @@ public void multipleFilesOneMatchEntireLinesFlag() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, one match, multiple flags")
public void multipleFilesOneMatchMultipleFlags() {
String expected = "paradise-lost.txt:4:With loss of Eden, till one greater Man";
@@ -407,6 +430,7 @@ public void multipleFilesOneMatchMultipleFlags() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, no matches, various flags")
public void multipleFilesNoMatchesVariousFlags() {
String expected = "";
@@ -421,6 +445,7 @@ public void multipleFilesNoMatchesVariousFlags() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, several matches, file flag takes precedence over line number flag")
public void multipleFilesSeveralMatchesFileFlagTakesPrecedenceOverLineNumberFlag() {
String expected = "iliad.txt\n"
+ "paradise-lost.txt";
@@ -436,6 +461,7 @@ public void multipleFilesSeveralMatchesFileFlagTakesPrecedenceOverLineNumberFlag
@Disabled("Remove to run test")
@Test
+ @DisplayName("Multiple files, several matches, inverted and match entire lines flags")
public void multipleFilesSeveralMatchesInvertedAndMatchEntireLinesFlags() {
String expected = "iliad.txt:Achilles sing, O Goddess! Peleus' son;\n"
+ "iliad.txt:His wrath pernicious, who ten thousand woes\n"
diff --git a/exercises/practice/hamming/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/hamming/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/hamming/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/hamming/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/hamming/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/hamming/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/hamming/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/hamming/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/hamming/gradlew b/exercises/practice/hamming/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/hamming/gradlew
+++ b/exercises/practice/hamming/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/hamming/gradlew.bat b/exercises/practice/hamming/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/hamming/gradlew.bat
+++ b/exercises/practice/hamming/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/hamming/src/test/java/HammingTest.java b/exercises/practice/hamming/src/test/java/HammingTest.java
index 5f9082e35..26f22491f 100644
--- a/exercises/practice/hamming/src/test/java/HammingTest.java
+++ b/exercises/practice/hamming/src/test/java/HammingTest.java
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -7,36 +8,42 @@
public class HammingTest {
@Test
+ @DisplayName("empty strands")
public void testNoDistanceBetweenEmptyStrands() {
assertThat(new Hamming("", "").getHammingDistance()).isEqualTo(0);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("single letter identical strands")
public void testNoDistanceBetweenShortIdenticalStrands() {
assertThat(new Hamming("A", "A").getHammingDistance()).isEqualTo(0);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("single letter different strands")
public void testCompleteDistanceInSingleLetterDifferentStrands() {
assertThat(new Hamming("G", "T").getHammingDistance()).isEqualTo(1);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("long identical strands")
public void testDistanceInLongIdenticalStrands() {
assertThat(new Hamming("GGACTGAAATCTG", "GGACTGAAATCTG").getHammingDistance()).isEqualTo(0);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("long different strands")
public void testDistanceInLongDifferentStrands() {
assertThat(new Hamming("GGACGGATTCTG", "AGGACGGATTCT").getHammingDistance()).isEqualTo(9);
}
@Disabled("Remove to run test")
@Test
+ @DisplayName("disallow first strand longer")
public void testValidatesFirstStrandNotLonger() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> new Hamming("AATG", "AAA"))
@@ -45,6 +52,7 @@ public void testValidatesFirstStrandNotLonger() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("disallow second strand longer")
public void testValidatesSecondStrandNotLonger() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> new Hamming("ATA", "AGTG"))
@@ -53,6 +61,7 @@ public void testValidatesSecondStrandNotLonger() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("disallow left empty strand")
public void testDisallowLeftEmptyStrand() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> new Hamming("", "G"))
@@ -61,6 +70,7 @@ public void testDisallowLeftEmptyStrand() {
@Disabled("Remove to run test")
@Test
+ @DisplayName("disallow right empty strand")
public void testDisallowRightEmptyStrand() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> new Hamming("G", ""))
diff --git a/exercises/practice/hangman/build.gradle b/exercises/practice/hangman/build.gradle
index 15df104cc..a55dc26f3 100644
--- a/exercises/practice/hangman/build.gradle
+++ b/exercises/practice/hangman/build.gradle
@@ -12,6 +12,8 @@ dependencies {
testImplementation platform("org.junit:junit-bom:5.10.0")
testImplementation "org.junit.jupiter:junit-jupiter"
testImplementation "org.assertj:assertj-core:3.25.1"
+
+ testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
test {
diff --git a/exercises/practice/hangman/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/hangman/gradle/wrapper/gradle-wrapper.jar
index e6441136f..f8e1ee312 100644
Binary files a/exercises/practice/hangman/gradle/wrapper/gradle-wrapper.jar and b/exercises/practice/hangman/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/exercises/practice/hangman/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/hangman/gradle/wrapper/gradle-wrapper.properties
index 2deab89d5..4d97ea344 100644
--- a/exercises/practice/hangman/gradle/wrapper/gradle-wrapper.properties
+++ b/exercises/practice/hangman/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/exercises/practice/hangman/gradlew b/exercises/practice/hangman/gradlew
index 1aa94a426..adff685a0 100755
--- a/exercises/practice/hangman/gradlew
+++ b/exercises/practice/hangman/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/exercises/practice/hangman/gradlew.bat b/exercises/practice/hangman/gradlew.bat
index 25da30dbd..c4bdd3ab8 100644
--- a/exercises/practice/hangman/gradlew.bat
+++ b/exercises/practice/hangman/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/exercises/practice/hangman/src/test/java/HangmanTest.java b/exercises/practice/hangman/src/test/java/HangmanTest.java
index df60dbee9..d4bbe13da 100644
--- a/exercises/practice/hangman/src/test/java/HangmanTest.java
+++ b/exercises/practice/hangman/src/test/java/HangmanTest.java
@@ -1,8 +1,10 @@
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.disposables.Disposable;
+
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
@@ -22,6 +24,7 @@ public void init() {
}
@Test
+ @DisplayName("Initial game state is set correctly")
public void initialization() {
Observable