From 10c76c88bb44837dd46901bcd8a445c3bbf32ca2 Mon Sep 17 00:00:00 2001 From: kornaa Date: Thu, 14 May 2026 18:34:27 +0200 Subject: [PATCH 01/13] Added GitHub Actions CI pipeline --- .vscode/.github/workflows/maven.yml | 35 ++++ .vscode/launch.json | 260 ++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 .vscode/.github/workflows/maven.yml create mode 100644 .vscode/launch.json diff --git a/.vscode/.github/workflows/maven.yml b/.vscode/.github/workflows/maven.yml new file mode 100644 index 000000000..df7f1585a --- /dev/null +++ b/.vscode/.github/workflows/maven.yml @@ -0,0 +1,35 @@ +name: Java CI with Maven + +on: +push: +branches: +- main +- master +pull_request: +branches: +- main +- master + +jobs: +build: + +``` +runs-on: ubuntu-latest + +steps: +- name: Checkout repository + uses: actions/checkout@v4 + +- name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'temurin' + +- name: Build with Maven + run: mvn clean install + +- name: Run tests + run: mvn test +``` + diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..308dbda25 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,260 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "java", + "name": "Current File", + "request": "launch", + "mainClass": "${file}" + }, + { + "type": "java", + "name": "CIELABColorSpace", + "request": "launch", + "mainClass": "org.jhotdraw.color.CIELABColorSpace", + "projectName": "jhotdraw-gui" + }, + { + "type": "java", + "name": "CIELCHabColorSpace", + "request": "launch", + "mainClass": "org.jhotdraw.color.CIELCHabColorSpace", + "projectName": "jhotdraw-gui" + }, + { + "type": "java", + "name": "EditCanvasPanel", + "request": "launch", + "mainClass": "org.jhotdraw.gui.action.EditCanvasPanel", + "projectName": "jhotdraw-gui" + }, + { + "type": "java", + "name": "CIEXYChromaticityDiagram", + "request": "launch", + "mainClass": "org.jhotdraw.samples.color.CIEXYChromaticityDiagram", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "JMixer", + "request": "launch", + "mainClass": "org.jhotdraw.samples.color.JMixer", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "WheelsAndSlidersMain", + "request": "launch", + "mainClass": "org.jhotdraw.samples.color.WheelsAndSlidersMain", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "FontChooserMain", + "request": "launch", + "mainClass": "org.jhotdraw.samples.font.FontChooserMain", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "ActivityMonitorSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.ActivityMonitorSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "AnimationSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.AnimationSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "BezierDemo", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.BezierDemo", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "ConnectingFiguresSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.ConnectingFiguresSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "CreationToolSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.CreationToolSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "DefaultDOMStorableSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.DefaultDOMStorableSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "DnDMultiEditorSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.DnDMultiEditorSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "EditorSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.EditorSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "FileIconsSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.FileIconsSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "LabeledLineConnectionFigureSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.LabeledLineConnectionFigureSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "LayouterSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.LayouterSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "MovableChildFiguresSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.MovableChildFiguresSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "MovableChildFiguresSampleWithAbstractDrawingView", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.MovableChildFiguresSampleWithAbstractDrawingView", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "MovableChildFiguresSampleWithDelegatorDrawingView", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.MovableChildFiguresSampleWithDelegatorDrawingView", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "MultiEditorSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.MultiEditorSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "SVGDrawingPanelSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.SVGDrawingPanelSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "SelectionToolSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.SelectionToolSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "SmartConnectionFigureSample", + "request": "launch", + "mainClass": "org.jhotdraw.samples.mini.SmartConnectionFigureSample", + "projectName": "jhotdraw-samples-mini" + }, + { + "type": "java", + "name": "Main", + "request": "launch", + "mainClass": "org.jhotdraw.samples.draw.Main", + "projectName": "jhotdraw-samples-misc" + }, + { + "type": "java", + "name": "Main(1)", + "request": "launch", + "mainClass": "org.jhotdraw.samples.net.Main", + "projectName": "jhotdraw-samples-misc" + }, + { + "type": "java", + "name": "NetApplet", + "request": "launch", + "mainClass": "org.jhotdraw.samples.net.NetApplet", + "projectName": "jhotdraw-samples-misc" + }, + { + "type": "java", + "name": "Main(2)", + "request": "launch", + "mainClass": "org.jhotdraw.samples.odg.Main", + "projectName": "jhotdraw-samples-misc" + }, + { + "type": "java", + "name": "Main(3)", + "request": "launch", + "mainClass": "org.jhotdraw.samples.pert.Main", + "projectName": "jhotdraw-samples-misc" + }, + { + "type": "java", + "name": "PertApplet", + "request": "launch", + "mainClass": "org.jhotdraw.samples.pert.PertApplet", + "projectName": "jhotdraw-samples-misc" + }, + { + "type": "java", + "name": "Main(4)", + "request": "launch", + "mainClass": "org.jhotdraw.samples.svg.Main", + "projectName": "jhotdraw-samples-misc" + }, + { + "type": "java", + "name": "SVGApplet", + "request": "launch", + "mainClass": "org.jhotdraw.samples.svg.SVGApplet", + "projectName": "jhotdraw-samples-misc" + }, + { + "type": "java", + "name": "Main(5)", + "request": "launch", + "mainClass": "org.jhotdraw.samples.teddy.Main", + "projectName": "jhotdraw-samples-misc" + }, + { + "type": "java", + "name": "Bezier", + "request": "launch", + "mainClass": "org.jhotdraw.geom.Bezier", + "projectName": "jhotdraw-utils" + } + ] +} \ No newline at end of file From 0094398904817de5a6ae814391942fcb93f993c2 Mon Sep 17 00:00:00 2001 From: kornaa Date: Thu, 14 May 2026 19:06:56 +0200 Subject: [PATCH 02/13] Removed broken workflow and added fixed CI pipeline --- .github/workflows/maven.yml | 41 +++++++++++++++++++++++++++++ .vscode/.github/workflows/maven.yml | 35 ------------------------ 2 files changed, 41 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/maven.yml delete mode 100644 .vscode/.github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 000000000..ee7041a92 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,41 @@ +name: Java CI with Maven + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + packages: read + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '17' + cache: maven + + - name: Configure Maven settings + run: | + mkdir -p ~/.m2 + cp .maven-settings.xml ~/.m2/settings.xml + + - name: Build project + run: mvn -B clean package --file pom.xml + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Execute tests automatically + run: mvn -B test --file pom.xml + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.vscode/.github/workflows/maven.yml b/.vscode/.github/workflows/maven.yml deleted file mode 100644 index df7f1585a..000000000 --- a/.vscode/.github/workflows/maven.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Java CI with Maven - -on: -push: -branches: -- main -- master -pull_request: -branches: -- main -- master - -jobs: -build: - -``` -runs-on: ubuntu-latest - -steps: -- name: Checkout repository - uses: actions/checkout@v4 - -- name: Set up JDK 11 - uses: actions/setup-java@v4 - with: - java-version: '11' - distribution: 'temurin' - -- name: Build with Maven - run: mvn clean install - -- name: Run tests - run: mvn test -``` - From 0e1d9f40f341082ac550a123bb6567bc9f3c58a0 Mon Sep 17 00:00:00 2001 From: kornaa Date: Thu, 14 May 2026 20:37:29 +0200 Subject: [PATCH 03/13] Create maven-publish.yml test --- .github/workflows/maven-publish.yml | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/maven-publish.yml diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml new file mode 100644 index 000000000..64b848b61 --- /dev/null +++ b/.github/workflows/maven-publish.yml @@ -0,0 +1,34 @@ +# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created +# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path + +name: Maven Package + +on: + release: + types: [created] + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'temurin' + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file + + - name: Build with Maven + run: mvn -B package --file pom.xml + + - name: Publish to GitHub Packages Apache Maven + run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml + env: + GITHUB_TOKEN: ${{ github.token }} From b44745948cd9c2ea7243ee95e2d2a9d85f4c5438 Mon Sep 17 00:00:00 2001 From: kornaa Date: Thu, 14 May 2026 20:43:26 +0200 Subject: [PATCH 04/13] Trigger workflow --- .github/workflows/maven.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index ee7041a92..1c5ad9284 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -38,4 +38,5 @@ jobs: - name: Execute tests automatically run: mvn -B test --file pom.xml env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# test \ No newline at end of file From 8859e87255131e8bb5ea742c1ef8faabbece4532 Mon Sep 17 00:00:00 2001 From: kornaa Date: Thu, 14 May 2026 20:44:50 +0200 Subject: [PATCH 05/13] Trigger workflow --- .github/workflows/maven-publish.yml | 1 + .github/workflows/maven.yml | 42 ----------------------------- 2 files changed, 1 insertion(+), 42 deletions(-) delete mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index 64b848b61..bb2ec02ef 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -32,3 +32,4 @@ jobs: run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml env: GITHUB_TOKEN: ${{ github.token }} +#test \ No newline at end of file diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml deleted file mode 100644 index 1c5ad9284..000000000 --- a/.github/workflows/maven.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Java CI with Maven - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -permissions: - contents: read - packages: read - -jobs: - build-and-test: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: '17' - cache: maven - - - name: Configure Maven settings - run: | - mkdir -p ~/.m2 - cp .maven-settings.xml ~/.m2/settings.xml - - - name: Build project - run: mvn -B clean package --file pom.xml - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Execute tests automatically - run: mvn -B test --file pom.xml - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -# test \ No newline at end of file From 7b612308e2ef7feccbe49f0624e4de2878325d5a Mon Sep 17 00:00:00 2001 From: kornaa Date: Thu, 14 May 2026 20:46:19 +0200 Subject: [PATCH 06/13] Create maven.yml test v2 --- .github/workflows/maven.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 000000000..bc5bb6dd2 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,35 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Java CI with Maven + +on: + push: + branches: [ "develop" ] + pull_request: + branches: [ "develop" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn -B package --file pom.xml + + # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive + - name: Update dependency graph + uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 From e2019e970370193f8575aeef434148f233a369ba Mon Sep 17 00:00:00 2001 From: kornaa Date: Thu, 14 May 2026 20:47:26 +0200 Subject: [PATCH 07/13] Trigger workflow v2 --- .github/workflows/maven-publish.yml | 35 ----------------------------- .github/workflows/maven.yml | 1 + 2 files changed, 1 insertion(+), 35 deletions(-) delete mode 100644 .github/workflows/maven-publish.yml diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml deleted file mode 100644 index bb2ec02ef..000000000 --- a/.github/workflows/maven-publish.yml +++ /dev/null @@ -1,35 +0,0 @@ -# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created -# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path - -name: Maven Package - -on: - release: - types: [created] - -jobs: - build: - - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - uses: actions/checkout@v4 - - name: Set up JDK 11 - uses: actions/setup-java@v4 - with: - java-version: '11' - distribution: 'temurin' - server-id: github # Value of the distributionManagement/repository/id field of the pom.xml - settings-path: ${{ github.workspace }} # location for the settings.xml file - - - name: Build with Maven - run: mvn -B package --file pom.xml - - - name: Publish to GitHub Packages Apache Maven - run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml - env: - GITHUB_TOKEN: ${{ github.token }} -#test \ No newline at end of file diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index bc5bb6dd2..d50ab9eee 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -33,3 +33,4 @@ jobs: # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - name: Update dependency graph uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 +#test \ No newline at end of file From a67d1fd477daa8bd29f20c25e47efb00d27a3500 Mon Sep 17 00:00:00 2001 From: kornaa Date: Thu, 14 May 2026 20:53:37 +0200 Subject: [PATCH 08/13] Fixed workflow branch trigger --- .github/workflows/maven.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index d50ab9eee..79fa1c258 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -10,9 +10,9 @@ name: Java CI with Maven on: push: - branches: [ "develop" ] + branches: [ "Kornelia" ] pull_request: - branches: [ "develop" ] + branches: [ "Kornelia" ] jobs: build: @@ -24,7 +24,7 @@ jobs: - name: Set up JDK 17 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '11' distribution: 'temurin' cache: maven - name: Build with Maven From 5e89896fd028a99363cf921a0b8f09d90991b815 Mon Sep 17 00:00:00 2001 From: kornaa Date: Thu, 14 May 2026 21:04:43 +0200 Subject: [PATCH 09/13] deleting the graph part --- .github/workflows/maven.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 79fa1c258..d53a3f0d6 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK 11 uses: actions/setup-java@v4 with: java-version: '11' @@ -30,7 +30,4 @@ jobs: - name: Build with Maven run: mvn -B package --file pom.xml - # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - - name: Update dependency graph - uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 #test \ No newline at end of file From c40065a96b19e362a9576238ee90f07c51c80e0b Mon Sep 17 00:00:00 2001 From: kornaa Date: Sun, 17 May 2026 14:32:58 +0200 Subject: [PATCH 10/13] Refactored PropertyChangeListener to lambda --- .../org/jhotdraw/action/edit/UndoAction.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/UndoAction.java b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/UndoAction.java index 74c4f2cea..6f0d4bac7 100644 --- a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/UndoAction.java +++ b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/UndoAction.java @@ -36,15 +36,17 @@ public class UndoAction extends AbstractViewAction { private static final long serialVersionUID = 1L; public static final String ID = "edit.undo"; private ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.action.Labels"); - private PropertyChangeListener redoActionPropertyListener = new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - String name = evt.getPropertyName(); - if ((name == null && AbstractAction.NAME == null) || (name != null && name.equals(AbstractAction.NAME))) { - putValue(AbstractAction.NAME, evt.getNewValue()); - } else if ("enabled".equals(name)) { - updateEnabledState(); - } + private transient PropertyChangeListener redoActionPropertyListener = evt -> { + String name = evt.getPropertyName(); + + if ((name == null && AbstractAction.NAME == null) + || (name != null && name.equals(AbstractAction.NAME))) { + + putValue(AbstractAction.NAME, evt.getNewValue()); + + } else if ("enabled".equals(name)) { + + updateEnabledState(); } }; From 904e644bd47924534d7f03dfb099020bf9661f39 Mon Sep 17 00:00:00 2001 From: kornaa Date: Fri, 22 May 2026 22:30:35 +0200 Subject: [PATCH 11/13] Add unit and BDD tests for UndoRedoManager - UndoRedoManagerTest: 4 JUnit4 unit tests covering best-case and boundary scenarios for undo/redo/discard behaviour - UndoRedoManagerBDDTest: 4 JGiven BDD scenarios mapped from user story (As a drawing user I want to undo/redo actions) - Labels.properties added to test resources to fix resource bundle error during test initialisation --- .../jhotdraw/undo/UndoRedoManagerTest.java | 98 +++++++++++++++++++ .../org/jhotdraw/undo/Labels.properties | 4 + 2 files changed, 102 insertions(+) create mode 100644 jhotdraw-utils/src/test/java/org/jhotdraw/undo/UndoRedoManagerTest.java create mode 100644 jhotdraw-utils/src/test/resources/org/jhotdraw/undo/Labels.properties diff --git a/jhotdraw-utils/src/test/java/org/jhotdraw/undo/UndoRedoManagerTest.java b/jhotdraw-utils/src/test/java/org/jhotdraw/undo/UndoRedoManagerTest.java new file mode 100644 index 000000000..2ba07234a --- /dev/null +++ b/jhotdraw-utils/src/test/java/org/jhotdraw/undo/UndoRedoManagerTest.java @@ -0,0 +1,98 @@ +package org.jhotdraw.undo; + +import org.junit.*; +import javax.swing.undo.*; +import static org.junit.Assert.*; + + +public class UndoRedoManagerTest { + + private UndoRedoManager manager; + + + private static class SimpleEdit extends AbstractUndoableEdit { + private static final long serialVersionUID = 1L; + + } + + @Before + public void setUp() { + manager = new UndoRedoManager(); + } + + @After + public void tearDown() { + manager.discardAllEdits(); + } + + + // Test 1 — BEST CASE + // Adding a significant edit should make undo available. + + @Test + public void testAddEdit_EnablesUndo() { + // Initially nothing to undo + assertFalse("Nothing to undo on a fresh manager", manager.canUndo()); + + manager.addEdit(new SimpleEdit()); + + // After adding an edit, undo must be possible + assertTrue("Undo should be available after adding an edit", manager.canUndo()); + // And the undo action button should be enabled + assertTrue("UndoAction should be enabled", manager.getUndoAction().isEnabled()); + // Redo has nothing to replay yet + assertFalse("Redo should NOT be available before any undo", manager.canRedo()); + } + + + // Test 2 — BEST CASE + // After undo, redo becomes available; after redo, undo is back. + + @Test + public void testUndoThenRedo_TogglesAvailability() { + manager.addEdit(new SimpleEdit()); + + // --- undo --- + manager.undo(); + assertFalse("Undo should NOT be available after undoing the only edit", + manager.canUndo()); + assertTrue("Redo should be available after undo", manager.canRedo()); + assertTrue("RedoAction should be enabled", manager.getRedoAction().isEnabled()); + + // --- redo --- + manager.redo(); + assertTrue("Undo should be available again after redo", manager.canUndo()); + assertFalse("Redo should NOT be available after redo", manager.canRedo()); + } + + // Test 3 — BOUNDARY CASE + // Calling undo on an empty manager must throw CannotUndoException. + + @Test(expected = CannotUndoException.class) + public void testUndo_OnEmptyManager_ThrowsException() { + // No edits added — undo must always throw here + manager.undo(); + } + + // + // Test 4 — BOUNDARY CASE + // discardAllEdits resets everything: no undo, no redo, and hasSignificantEdits goes back to false. + + @Test + public void testDiscardAllEdits_ResetsState() { + manager.addEdit(new SimpleEdit()); + assertTrue("Sanity check: should have significant edits", manager.hasSignificantEdits()); + + manager.discardAllEdits(); + + // All three invariants must hold after discard + assertFalse("canUndo must be false after discard", manager.canUndo()); + assertFalse("canRedo must be false after discard", manager.canRedo()); + assertFalse("hasSignificantEdits must be false after discard", + manager.hasSignificantEdits()); + assertFalse("UndoAction must be disabled after discard", + manager.getUndoAction().isEnabled()); + assertFalse("RedoAction must be disabled after discard", + manager.getRedoAction().isEnabled()); + } +} \ No newline at end of file diff --git a/jhotdraw-utils/src/test/resources/org/jhotdraw/undo/Labels.properties b/jhotdraw-utils/src/test/resources/org/jhotdraw/undo/Labels.properties new file mode 100644 index 000000000..ef3c9d4ce --- /dev/null +++ b/jhotdraw-utils/src/test/resources/org/jhotdraw/undo/Labels.properties @@ -0,0 +1,4 @@ +edit.undo.text=Undo +edit.redo.text=Redo +edit.undo=Undo +edit.redo=Redo From 6baa11e692608836d83af01018ae8247cb7180ee Mon Sep 17 00:00:00 2001 From: kornaa Date: Fri, 22 May 2026 22:35:08 +0200 Subject: [PATCH 12/13] Add unit and BDD tests for UndoRedoManager second --- .../jhotdraw/undo/UndoRedoManagerBDDTest.java | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 jhotdraw-utils/src/test/resources/org/jhotdraw/undo/UndoRedoManagerBDDTest.java diff --git a/jhotdraw-utils/src/test/resources/org/jhotdraw/undo/UndoRedoManagerBDDTest.java b/jhotdraw-utils/src/test/resources/org/jhotdraw/undo/UndoRedoManagerBDDTest.java new file mode 100644 index 000000000..592bbf6a3 --- /dev/null +++ b/jhotdraw-utils/src/test/resources/org/jhotdraw/undo/UndoRedoManagerBDDTest.java @@ -0,0 +1,187 @@ +package org.jhotdraw.undo; + +import com.tngtech.jgiven.Stage; +import com.tngtech.jgiven.annotation.As; +import com.tngtech.jgiven.annotation.ExpectedScenarioState; +import com.tngtech.jgiven.annotation.ProvidedScenarioState; +import com.tngtech.jgiven.junit.ScenarioTest; +import org.junit.Test; + +import javax.swing.undo.AbstractUndoableEdit; + +import static org.assertj.core.api.Assertions.assertThat; + + +@As("Undo/Redo Functionality") +public class UndoRedoManagerBDDTest + extends ScenarioTest { + + + static class DrawingEdit extends AbstractUndoableEdit { + private static final long serialVersionUID = 1L; + } + + // Scenario 1 — Acceptance Criterion 1 + // The user can undo the latest action. + @Test + @As("User can undo the latest drawing action") + public void user_can_undo_the_latest_action() { + given().a_fresh_undo_manager() + .and().the_user_has_performed_a_drawing_action(); + + when().the_user_triggers_undo(); + + then().undo_is_no_longer_available() + .and().redo_becomes_available(); + } + + + // Scenario 2 — Acceptance Criterion 2 + // The user can redo an undone action. + + @Test + @As("User can redo a previously undone action") + public void user_can_redo_an_undone_action() { + given().a_fresh_undo_manager() + .and().the_user_has_performed_a_drawing_action(); + + when().the_user_triggers_undo() + .and().the_user_triggers_redo(); + + then().undo_is_available_again() + .and().redo_is_no_longer_available(); + } + + + // Scenario 3 — Acceptance Criterion 3 + // Multiple undo/redo operations are supported. + + @Test + @As("User can undo and redo multiple drawing actions") + public void user_can_undo_multiple_actions() { + given().a_fresh_undo_manager() + .and().the_user_has_performed_$_drawing_actions(3); + + when().the_user_triggers_undo() + .and().the_user_triggers_undo(); + + then().undo_is_still_available_for_remaining_edits() + .and().redo_becomes_available(); + } + + + // Scenario 4 — Acceptance Criterion 4 + // State is correctly reset when edits are discarded (e.g. new file). + + @Test + @As("Manager resets correctly when all edits are discarded") + public void manager_resets_state_after_discard() { + given().a_fresh_undo_manager() + .and().the_user_has_performed_a_drawing_action(); + + when().all_edits_are_discarded(); + + then().neither_undo_nor_redo_is_available(); + } + + + // STAGES + + + public static class GivenStage extends Stage { + + @ProvidedScenarioState + UndoRedoManager manager; + + public GivenStage a_fresh_undo_manager() { + manager = new UndoRedoManager(); + return self(); + } + + public GivenStage the_user_has_performed_a_drawing_action() { + manager.addEdit(new DrawingEdit()); + return self(); + } + + public GivenStage the_user_has_performed_$_drawing_actions(int count) { + for (int i = 0; i < count; i++) { + manager.addEdit(new DrawingEdit()); + } + return self(); + } + } + + public static class WhenStage extends Stage { + + @ExpectedScenarioState + UndoRedoManager manager; + + public WhenStage the_user_triggers_undo() { + manager.undo(); + return self(); + } + + public WhenStage the_user_triggers_redo() { + manager.redo(); + return self(); + } + + public WhenStage all_edits_are_discarded() { + manager.discardAllEdits(); + return self(); + } + } + + public static class ThenStage extends Stage { + + @ExpectedScenarioState + UndoRedoManager manager; + + public ThenStage undo_is_no_longer_available() { + assertThat(manager.canUndo()) + .as("Undo should not be available after undoing the only edit") + .isFalse(); + return self(); + } + + public ThenStage redo_becomes_available() { + assertThat(manager.canRedo()) + .as("Redo should be available after an undo") + .isTrue(); + return self(); + } + + public ThenStage undo_is_available_again() { + assertThat(manager.canUndo()) + .as("Undo should be available again after redo") + .isTrue(); + return self(); + } + + public ThenStage redo_is_no_longer_available() { + assertThat(manager.canRedo()) + .as("Redo should not be available after redoing") + .isFalse(); + return self(); + } + + public ThenStage undo_is_still_available_for_remaining_edits() { + assertThat(manager.canUndo()) + .as("Undo should still be available (1 edit remains)") + .isTrue(); + return self(); + } + + public ThenStage neither_undo_nor_redo_is_available() { + assertThat(manager.canUndo()) + .as("Undo must be disabled after discard") + .isFalse(); + assertThat(manager.canRedo()) + .as("Redo must be disabled after discard") + .isFalse(); + return self(); + } + } +} \ No newline at end of file From 7a2b337974ecea6e6e5492f278a8708cd1f9381e Mon Sep 17 00:00:00 2001 From: kornaa Date: Fri, 22 May 2026 22:50:56 +0200 Subject: [PATCH 13/13] Add JUnit4 unit tests and JGiven BDD tests for UndoRedoManager - UndoRedoManagerTest: 4 JUnit4 tests (best-case + boundary) - UndoRedoManagerBDDTest: 4 JGiven BDD scenarios mapped from user story - Labels.properties added to test resources to fix resource bundle error - pom.xml updated with JUnit4, JGiven and AssertJ dependencies --- jhotdraw-utils/pom.xml | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/jhotdraw-utils/pom.xml b/jhotdraw-utils/pom.xml index b1b2faf01..1f33e837c 100644 --- a/jhotdraw-utils/pom.xml +++ b/jhotdraw-utils/pom.xml @@ -15,5 +15,48 @@ 6.8.21 test + + + junit + junit + 4.13.2 + test + + + + com.tngtech.jgiven + jgiven-junit + 1.3.1 + test + + + + + org.assertj + assertj-core + 3.25.3 + test + + + + + + + com.tngtech.jgiven + jgiven-maven-plugin + 1.3.1 + + + + report + + + + + html + + + + \ No newline at end of file