From 3cb5020017c8a1c8944d88166763f9ac4a904639 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Thu, 6 Aug 2026 19:23:06 +0200 Subject: [PATCH 01/10] #39: Requirements and design for the transitive filter. --- ...ransitive-tracing-defects-in-run-config.md | 58 +++++++++++++++++++ doc/design/architecture_decisions.md | 43 ++++++++++++++ doc/design/runtime_view.md | 26 ++++++++- doc/system_requirements.md | 47 +++++++++++++++ 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 doc/changesets/72-add-filter-for-transitive-tracing-defects-in-run-config.md diff --git a/doc/changesets/72-add-filter-for-transitive-tracing-defects-in-run-config.md b/doc/changesets/72-add-filter-for-transitive-tracing-defects-in-run-config.md new file mode 100644 index 0000000..11c1e75 --- /dev/null +++ b/doc/changesets/72-add-filter-for-transitive-tracing-defects-in-run-config.md @@ -0,0 +1,58 @@ +W# GH-72 Add filter for transitive tracing defects in run config + +## Goal + +Let users choose whether the trace result views should show transitive defects, with the checkbox defaulting on in run configuration templates so the existing defect-oriented view stays available while the UI can be narrowed to direct defects when needed. + +## Scope + +In scope: + +* Add a run-configuration result-view checkbox for showing or hiding transitive defects. +* Default the new setting to show transitive defects in the bundled run configuration templates. +* Apply the setting in the IntelliJ Test Runner UI presentation. +* Apply the setting in the plain-text trace result presentation. +* Document the new behavior in traced requirements and the runtime design. + +Out of scope: + +* Changing OpenFastTrace trace evaluation or the transitive-defect detection rules. +* Adding an instant toggle in the test runner tree itself. +* Reworking the existing trace result views beyond the filter behavior needed here. + +## Design References + +* [System Requirements](../system_requirements.md) +* [Quality Requirements](../design/quality_requirements.md) +* [Building Block View](../design/building_block_view.md) +* [Runtime View](../design/runtime_view.md) + +## Strategy + +Treat the filter as a presentation concern that is stored with the run configuration, propagated into both trace presenters, and left out of the tracing engine. The implementation should keep direct defects visible, hide only transitive defects when the option is off, and preserve the existing default-on behavior in the preconfigured templates. + +## Task List + +- [ ] Create and checkout a new Git branch `feat/72-add-filter-for-transitive-tracing-defects-in-run-config` + +### Requirements And Design + +- [ ] Update `doc/system_requirements.md` with a run-configuration result-view requirement for showing or hiding transitive defects and scenarios for the default-on template behavior. +- [ ] Update `doc/design/runtime_view.md` with a design item describing how the stored result-view filter is applied in the test runner tree and plain-text presenter. +- [ ] Update `doc/design/building_block_view.md` if needed to show the run-configuration/settings-editor and presenter wiring for the new filter. +- [ ] Stop and ask user for a review of the system requirements and design. + +### Implementation + +- [ ] Extend the trace settings model and run-configuration persistence with a transitive-defect visibility flag. +- [ ] Add the checkbox to the run-configuration settings editor and default it on for the existing templates. +- [ ] Filter transitive defects out of the test-runner tree and plain-text output when the setting is off. +- [ ] Keep direct defects, navigation, and overall trace failure behavior unchanged. + +### Verification + +- [ ] Add focused tests for settings persistence, template defaults, and editor round-tripping of the transitive-defect flag. +- [ ] Add presenter and tree-mapper tests proving transitive defects are shown or hidden according to the saved setting. +- [ ] Add plain-text renderer or run-content tests proving the filtered output stays consistent with the configured result view. +- [ ] Keep the OpenFastTrace trace clean. +- [ ] Keep required build and plugin verification tasks green. diff --git a/doc/design/architecture_decisions.md b/doc/design/architecture_decisions.md index 984969c..d65580a 100644 --- a/doc/design/architecture_decisions.md +++ b/doc/design/architecture_decisions.md @@ -174,6 +174,49 @@ We add no "needs" here, since we cannot trace into dependabot. Tags: Build, Security, Dependabot +## Trace Presentation Decisions + +### How Does The Plugin Handle Transitive Defects In Trace Result Views? + +The plugin needs a way to reduce trace-result noise when users debug broken dependency chains. This decision is architecture-relevant because it affects: + +* how much noise every trace run exposes to the user while debugging a broken chain +* whether the same setting can drive both the Test Runner UI and plain-text trace output +* whether the project can keep transitive-defect detection in OpenFastTrace while changing only presentation + +Picking the wrong option here would be expensive to undo. A local-only workaround would leave the result views inconsistent, and a trace-engine change would spread through tracing, report rendering, and test coverage. Once the wrong behavior is baked into the result model or the trace engine, changing it later would require broad refactoring across the trace pipeline instead of a narrow presentation-layer adjustment. + +We considered the following alternatives: + +1. No filter. + + This produces too much noise. Debugging broken chains stays unnecessarily hard because direct defects are mixed with transitive defects that are only symptoms. + +1. Only an optical distinction without a filter. + + This looks better, but it still leaves the noise problem unsolved because transitive defects remain present in the result tree and report. + +1. Use the `ignored` status in the Test Runner UI. + + This looked visually good, but it did not work as a filter because the items below a transitive defect were still counted as successful. The instant filter could not hide the transitive item without also changing the status accounting under it. + +#### Transitive Defect Visibility Is Controlled By The Run Configuration +`dsn~transitive-defect-visibility-is-controlled-by-the-run-configuration~1` + +The trace result presentations read the saved `Show transitive defects` setting from the OpenFastTrace run configuration and use it to include or omit transitive defects before rendering the Test Runner UI or the plain-text report. + +Rationale: + +This keeps the transitive-defect filter in the presentation layer instead of changing trace evaluation, and it works consistently across both result views. The bundled run configuration templates initialize the setting to shown so the existing defect-oriented view remains the default. + +Comment: + +This decision does not change how OpenFastTrace detects transitive defects. It only changes whether the trace presenters render them. + +Needs: impl + +Tags: Trace, Run Configuration, UI + ## Test Framework Decisions ### Which JUnit Baseline Does the Plugin Use? diff --git a/doc/design/runtime_view.md b/doc/design/runtime_view.md index 11ecd7f..552ef52 100644 --- a/doc/design/runtime_view.md +++ b/doc/design/runtime_view.md @@ -404,6 +404,30 @@ Covers: Needs: impl, itest +### Hide Transitive Defects in Test Runner UI +`dsn~hide-transitive-defects-in-test-runner-ui~1` + +**Given** the trace test-runner presentation receives a structured OpenFastTrace trace result and the saved run-configuration setting disables transitive defects +**When** it maps the trace result to SM test runner nodes +**Then** it omits specification-item nodes that are identified as transitive defects while still creating nodes for direct defects and their trace links. + +Covers: +- `scn~hide-transitive-defects-in-test-runner-ui~1` + +Needs: impl, itest + +### Hide Transitive Defects in Plain Text Output +`dsn~hide-transitive-defects-in-plain-text-output~1` + +**Given** the plain-text trace presentation receives a structured OpenFastTrace trace result and the saved run-configuration setting disables transitive defects +**When** it prepares the OFT report settings for the plain-text renderer +**Then** it sets the base library's transitive-defect filter option so the rendered report omits transitive defects while still preserving direct-defect information and the existing summary for the remaining trace. + +Covers: +- `scn~hide-transitive-defects-in-plain-text-output~1` + +Needs: impl, itest + ### Trace Selected Project Resources `dsn~trace-selected-project-resources~2` @@ -631,7 +655,7 @@ Covers: Needs: impl, itest -No### Mark Transitive Defects in Test Runner UI +### Mark Transitive Defects in Test Runner UI `dsn~mark-transitive-defects-in-test-runner~1` **Given** the trace test-runner presentation creates a specification-item test node for a defective item that is identified as a transitive defect diff --git a/doc/system_requirements.md b/doc/system_requirements.md index cc306fc..bffc03f 100644 --- a/doc/system_requirements.md +++ b/doc/system_requirements.md @@ -1460,6 +1460,53 @@ Covers: Needs: dsn +#### Filter Transitive Defects in Trace Result View +`req~filter-transitive-defects-in-trace-result-view~1` + +The OpenFastTrace run configuration includes a `Show transitive defects` checkbox for the trace result view. When users leave the checkbox selected, the plugin shows transitive defects alongside direct defects in the configured result view. When users clear the checkbox, the plugin hides transitive defects so they can focus on the direct defects that still need fixing. + +Covers: +- `feat~oft-run-configurations~2` +- `feat~oft-test-runner-trace-results~1` + +Needs: scn + +#### Show Transitive Defects by Default in Run Configuration Templates +`scn~show-transitive-defects-by-default-in-run-configuration-templates~1` + +**Given** an IntelliJ project is open and a user creates a new OpenFastTrace run configuration from one of the bundled templates +**When** the configuration editor opens +**Then** the `Show transitive defects` checkbox is selected by default + +Covers: +- `req~filter-transitive-defects-in-trace-result-view~1` + +Needs: dsn + +#### Hide Transitive Defects in Test Runner UI +`scn~hide-transitive-defects-in-test-runner-ui~1` + +**Given** an IntelliJ project is open, an `OpenFastTrace` run configuration uses the IntelliJ Test Runner UI result view, and the `Show transitive defects` checkbox is cleared +**When** the user runs the configuration +**Then** the test runner tree omits transitive defects while still showing direct defects and their trace links + +Covers: +- `req~filter-transitive-defects-in-trace-result-view~1` + +Needs: dsn + +#### Hide Transitive Defects in Plain Text Output +`scn~hide-transitive-defects-in-plain-text-output~1` + +**Given** an IntelliJ project is open, an `OpenFastTrace` run configuration uses the plain text result view, and the `Show transitive defects` checkbox is cleared +**When** the user runs the configuration +**Then** the plain text report omits transitive defects while still showing direct defects and their trace links + +Covers: +- `req~filter-transitive-defects-in-trace-result-view~1` + +Needs: dsn + ### Show Plugin Logo in JetBrains Plugin Surfaces `scn~show-plugin-logo-in-jetbrains-plugin-surfaces~1` From 88dacc818f3e53e52557f7b7cf1dec493ff76580 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Thu, 6 Aug 2026 20:28:39 +0200 Subject: [PATCH 02/10] #39: Improved requirements and UI mockup. --- ...ransitive-tracing-defects-in-run-config.md | 26 +++++++++---------- doc/design/architecture_decisions.md | 2 +- doc/design/building_block_view.md | 1 + doc/design/runtime_view.md | 14 +++++++++- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/doc/changesets/72-add-filter-for-transitive-tracing-defects-in-run-config.md b/doc/changesets/72-add-filter-for-transitive-tracing-defects-in-run-config.md index 11c1e75..b9b5498 100644 --- a/doc/changesets/72-add-filter-for-transitive-tracing-defects-in-run-config.md +++ b/doc/changesets/72-add-filter-for-transitive-tracing-defects-in-run-config.md @@ -1,4 +1,4 @@ -W# GH-72 Add filter for transitive tracing defects in run config +# GH-72 Add filter for transitive tracing defects in run config ## Goal @@ -37,22 +37,22 @@ Treat the filter as a presentation concern that is stored with the run configura ### Requirements And Design -- [ ] Update `doc/system_requirements.md` with a run-configuration result-view requirement for showing or hiding transitive defects and scenarios for the default-on template behavior. -- [ ] Update `doc/design/runtime_view.md` with a design item describing how the stored result-view filter is applied in the test runner tree and plain-text presenter. +- [x] Update `doc/system_requirements.md` with a run-configuration result-view requirement for showing or hiding transitive defects and scenarios for the default-on template behavior. +- [x] Update `doc/design/runtime_view.md` with a design item describing how the stored result-view filter is applied in the test runner tree and plain-text presenter. - [ ] Update `doc/design/building_block_view.md` if needed to show the run-configuration/settings-editor and presenter wiring for the new filter. -- [ ] Stop and ask user for a review of the system requirements and design. +- [x] Stop and ask user for a review of the system requirements and design. ### Implementation -- [ ] Extend the trace settings model and run-configuration persistence with a transitive-defect visibility flag. -- [ ] Add the checkbox to the run-configuration settings editor and default it on for the existing templates. -- [ ] Filter transitive defects out of the test-runner tree and plain-text output when the setting is off. -- [ ] Keep direct defects, navigation, and overall trace failure behavior unchanged. +- [x] Extend the trace settings model and run-configuration persistence with a transitive-defect visibility flag. +- [x] Add the checkbox to the run-configuration settings editor and default it on for the existing templates. +- [x] Filter transitive defects out of the test-runner tree and plain-text output when the setting is off. +- [x] Keep direct defects, navigation, and overall trace failure behavior unchanged. ### Verification -- [ ] Add focused tests for settings persistence, template defaults, and editor round-tripping of the transitive-defect flag. -- [ ] Add presenter and tree-mapper tests proving transitive defects are shown or hidden according to the saved setting. -- [ ] Add plain-text renderer or run-content tests proving the filtered output stays consistent with the configured result view. -- [ ] Keep the OpenFastTrace trace clean. -- [ ] Keep required build and plugin verification tasks green. +- [x] Add focused tests for settings persistence, template defaults, and editor round-tripping of the transitive-defect flag. +- [x] Add presenter and tree-mapper tests proving transitive defects are shown or hidden according to the saved setting. +- [x] Add plain-text renderer or run-content tests proving the filtered output stays consistent with the configured result view. +- [x] Keep the OpenFastTrace trace clean. +- [x] Keep required build and plugin verification tasks green. diff --git a/doc/design/architecture_decisions.md b/doc/design/architecture_decisions.md index d65580a..0086f3d 100644 --- a/doc/design/architecture_decisions.md +++ b/doc/design/architecture_decisions.md @@ -184,7 +184,7 @@ The plugin needs a way to reduce trace-result noise when users debug broken depe * whether the same setting can drive both the Test Runner UI and plain-text trace output * whether the project can keep transitive-defect detection in OpenFastTrace while changing only presentation -Picking the wrong option here would be expensive to undo. A local-only workaround would leave the result views inconsistent, and a trace-engine change would spread through tracing, report rendering, and test coverage. Once the wrong behavior is baked into the result model or the trace engine, changing it later would require broad refactoring across the trace pipeline instead of a narrow presentation-layer adjustment. +Picking the wrong option here would be expensive to undo. A local-only workaround would leave the result views inconsistent and force users to learn two different behaviors. Burying the filter in the trace engine or result model would be harder still because that choice would spread into tracing, rendering, settings persistence, and tests, so correcting it later would require broad refactoring instead of a narrow presentation-layer change. We considered the following alternatives: diff --git a/doc/design/building_block_view.md b/doc/design/building_block_view.md index 601bf7b..2029bf0 100644 --- a/doc/design/building_block_view.md +++ b/doc/design/building_block_view.md @@ -464,6 +464,7 @@ scale 2 Result view: | () Plain text output . | (X) IntelliJ Test Runner UI . | . + . | [X] Include transitive defects } { diff --git a/doc/design/runtime_view.md b/doc/design/runtime_view.md index 552ef52..5bf45c3 100644 --- a/doc/design/runtime_view.md +++ b/doc/design/runtime_view.md @@ -404,6 +404,18 @@ Covers: Needs: impl, itest +### Show Transitive Defects by Default in Run Configuration Templates +`dsn~show-transitive-defects-by-default-in-run-configuration-templates~1` + +**Given** the run-configuration templates initialize a new OpenFastTrace run configuration +**When** the configuration editor opens for one of those templates +**Then** the `Show transitive defects` checkbox is selected so the default template behavior keeps transitive defects visible. + +Covers: +- `scn~show-transitive-defects-by-default-in-run-configuration-templates~1` + +Needs: impl, itest + ### Hide Transitive Defects in Test Runner UI `dsn~hide-transitive-defects-in-test-runner-ui~1` @@ -421,7 +433,7 @@ Needs: impl, itest **Given** the plain-text trace presentation receives a structured OpenFastTrace trace result and the saved run-configuration setting disables transitive defects **When** it prepares the OFT report settings for the plain-text renderer -**Then** it sets the base library's transitive-defect filter option so the rendered report omits transitive defects while still preserving direct-defect information and the existing summary for the remaining trace. +**Then** it passes the saved setting to the OpenFastTrace base library's report filter option so the rendered report omits transitive defects while still preserving direct-defect information and the existing summary for the remaining trace. Covers: - `scn~hide-transitive-defects-in-plain-text-output~1` From 7e4c4a2d9387fc39dc865cc31dcc381baf81a0de Mon Sep 17 00:00:00 2001 From: redcatbear Date: Thu, 6 Aug 2026 20:29:47 +0200 Subject: [PATCH 03/10] #39: Introduced filter for transitive dependencies in run configuration. --- .../trace/runconfig/OftRunConfiguration.java | 11 ++++++ .../runconfig/OftRunConfigurationType.java | 10 +++-- ...OftRunConfigurationSettingsEditorTest.java | 5 +++ .../runconfig/OftRunConfigurationTest.java | 38 ++++++++++++++----- 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfiguration.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfiguration.java index 253f136..4548139 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfiguration.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfiguration.java @@ -51,6 +51,7 @@ public OftTraceSettingsSnapshot snapshot() { state.getArtifactTypesText(), state.getTagsText(), state.isIncludeUntagged(), + state.isShowTransitiveDefects(), parseResultView(state.getResultView()) ); } @@ -63,6 +64,7 @@ public void updateFrom(final OftTraceSettingsSnapshot snapshot) { state.setArtifactTypesText(snapshot.artifactTypesText()); state.setTagsText(snapshot.tagsText()); state.setIncludeUntagged(snapshot.includeUntagged()); + state.setShowTransitiveDefects(snapshot.showTransitiveDefects()); state.setResultView(snapshot.resultView().name()); } @@ -114,6 +116,7 @@ private static final class State implements Serializable { private String artifactTypesText = OftTraceSettingsSnapshot.DEFAULT.artifactTypesText(); private String tagsText = OftTraceSettingsSnapshot.DEFAULT.tagsText(); private boolean includeUntagged = OftTraceSettingsSnapshot.DEFAULT.includeUntagged(); + private boolean showTransitiveDefects = OftTraceSettingsSnapshot.DEFAULT.showTransitiveDefects(); private String resultView = OftTraceSettingsSnapshot.DEFAULT.resultView().name(); public String getTraceScopeMode() { @@ -172,6 +175,14 @@ public void setIncludeUntagged(final boolean includeUntagged) { this.includeUntagged = includeUntagged; } + public boolean isShowTransitiveDefects() { + return showTransitiveDefects; + } + + public void setShowTransitiveDefects(final boolean showTransitiveDefects) { + this.showTransitiveDefects = showTransitiveDefects; + } + public String getResultView() { return resultView; } diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationType.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationType.java index d842b46..d452e00 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationType.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationType.java @@ -9,6 +9,7 @@ // [impl->dsn~openfasttrace-run-configuration~2] // [impl->dsn~use-run-configuration-templates~1] +// [impl->dsn~show-transitive-defects-by-default-in-run-configuration-templates~1] public final class OftRunConfigurationType extends ConfigurationTypeBase { public static final String ID = "OpenFastTraceRunConfiguration"; @@ -18,24 +19,25 @@ public OftRunConfigurationType() { addFactory(new OftRunConfigurationFactory(this, "User requirements", config -> { final OftTraceSettingsSnapshot snapshot = new OftTraceSettingsSnapshot( OftTraceScopeMode.SELECTED_RESOURCES, false, false, "doc/", "feat, req, scn, bconstr", "", - OftTraceResultView.TEST_RUNNER); + false, true, OftTraceResultView.TEST_RUNNER); config.updateFrom(snapshot); })); addFactory(new OftRunConfigurationFactory(this, "Design and above", config -> { final OftTraceSettingsSnapshot snapshot = new OftTraceSettingsSnapshot( OftTraceScopeMode.SELECTED_RESOURCES, false, false, "doc/", - "feat, req, scn, bconstr, arch, dsn, constr, bld", "", OftTraceResultView.TEST_RUNNER); + "feat, req, scn, bconstr, arch, dsn, constr, bld", "", false, true, OftTraceResultView.TEST_RUNNER); config.updateFrom(snapshot); })); addFactory(new OftRunConfigurationFactory(this, "Typical project", config -> { final OftTraceSettingsSnapshot snapshot = new OftTraceSettingsSnapshot( OftTraceScopeMode.SELECTED_RESOURCES, true, true, "doc/", "", "", - OftTraceResultView.TEST_RUNNER); + false, true, OftTraceResultView.TEST_RUNNER); config.updateFrom(snapshot); })); addFactory(new OftRunConfigurationFactory(this, "Unfiltered", config -> { final OftTraceSettingsSnapshot snapshot = new OftTraceSettingsSnapshot( - OftTraceScopeMode.WHOLE_PROJECT, false, false, ".", "", "", OftTraceResultView.TEST_RUNNER); + OftTraceScopeMode.WHOLE_PROJECT, false, false, ".", "", "", false, true, + OftTraceResultView.TEST_RUNNER); config.updateFrom(snapshot); })); } diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationSettingsEditorTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationSettingsEditorTest.java index edcb570..37751d4 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationSettingsEditorTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationSettingsEditorTest.java @@ -40,6 +40,7 @@ public void testGivenEditorWhenResettingFromConfigurationThenItUpdatesUI() { "dsn", "mvp", true, + false, OftTraceResultView.TEST_RUNNER ); configuration.updateFrom(snapshot); @@ -56,6 +57,7 @@ public void testGivenEditorWhenResettingFromConfigurationThenItUpdatesUI() { () -> assertThat(uiSettings.artifactTypesText(), is(snapshot.artifactTypesText())), () -> assertThat(uiSettings.tagsText(), is(snapshot.tagsText())), () -> assertThat(uiSettings.includeUntagged(), is(snapshot.includeUntagged())), + () -> assertThat(uiSettings.showTransitiveDefects(), is(snapshot.showTransitiveDefects())), () -> assertThat(uiSettings.resultView(), is(snapshot.resultView())) ); } @@ -72,6 +74,7 @@ public void testGivenEditorWhenApplyingToConfigurationThenItUpdatesConfiguration "req", "tag", true, + false, OftTraceResultView.TEST_RUNNER ); editor.component.setSettings(snapshot); @@ -88,6 +91,7 @@ public void testGivenEditorWhenApplyingToConfigurationThenItUpdatesConfiguration () -> assertThat(stored.artifactTypesText(), is(snapshot.artifactTypesText())), () -> assertThat(stored.tagsText(), is(snapshot.tagsText())), () -> assertThat(stored.includeUntagged(), is(snapshot.includeUntagged())), + () -> assertThat(stored.showTransitiveDefects(), is(snapshot.showTransitiveDefects())), () -> assertThat(stored.resultView(), is(snapshot.resultView())) ); } @@ -103,6 +107,7 @@ public void testGivenEditorWithMissingAdditionalPathWhenUpdatingSettingsThenItSh "", "", false, + true, OftTraceResultView.TEST_RUNNER )); diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java index 06a891f..56702e5 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java @@ -29,7 +29,10 @@ public class OftRunConfigurationTest extends AbstractOftPlatformTestCase { public void testGivenNewRunConfigurationWhenReadingSnapshotThenItDefaultsToTestRunner() { final OftRunConfiguration configuration = createConfiguration("Test"); - assertThat(configuration.snapshot().resultView(), is(OftTraceResultView.TEST_RUNNER)); + Assertions.assertAll( + () -> assertThat(configuration.snapshot().resultView(), is(OftTraceResultView.TEST_RUNNER)), + () -> assertThat(configuration.snapshot().showTransitiveDefects(), is(true)) + ); } // [itest->dsn~select-test-runner-trace-result-view~1] @@ -44,6 +47,7 @@ public void testGivenRunConfigurationWhenUpdatingFromSnapshotThenItStoresTheSett "dsn", "mvp", true, + false, OftTraceResultView.TEST_RUNNER ); @@ -58,6 +62,7 @@ public void testGivenRunConfigurationWhenUpdatingFromSnapshotThenItStoresTheSett () -> assertThat(stored.artifactTypesText(), is(snapshot.artifactTypesText())), () -> assertThat(stored.tagsText(), is(snapshot.tagsText())), () -> assertThat(stored.includeUntagged(), is(snapshot.includeUntagged())), + () -> assertThat(stored.showTransitiveDefects(), is(snapshot.showTransitiveDefects())), () -> assertThat(stored.resultView(), is(snapshot.resultView())) ); } @@ -75,6 +80,7 @@ public void testGivenRunConfigurationWithSettingsWhenWritingAndReadingExternalTh "dsn", "mvp", true, + false, OftTraceResultView.TEST_RUNNER ); configuration.updateFrom(snapshot); @@ -94,6 +100,7 @@ public void testGivenRunConfigurationWithSettingsWhenWritingAndReadingExternalTh () -> assertThat(stored.artifactTypesText(), is(snapshot.artifactTypesText())), () -> assertThat(stored.tagsText(), is(snapshot.tagsText())), () -> assertThat(stored.includeUntagged(), is(snapshot.includeUntagged())), + () -> assertThat(stored.showTransitiveDefects(), is(snapshot.showTransitiveDefects())), () -> assertThat(stored.resultView(), is(snapshot.resultView())) ); } @@ -106,7 +113,10 @@ public void testGivenRunConfigurationWithNoStoredResultViewWhenReadingExternalTh configuration.readExternal(new Element("configuration")); - assertThat(configuration.snapshot().resultView(), is(OftTraceResultView.TEST_RUNNER)); + Assertions.assertAll( + () -> assertThat(configuration.snapshot().resultView(), is(OftTraceResultView.TEST_RUNNER)), + () -> assertThat(configuration.snapshot().showTransitiveDefects(), is(true)) + ); } // [itest->dsn~test-runner-as-default-run-configuration-result-view~1] @@ -121,7 +131,10 @@ public void testGivenRunConfigurationWithInvalidStoredResultViewWhenReadingExter configuration.readExternal(element); - assertThat(configuration.snapshot().resultView(), is(OftTraceResultView.TEST_RUNNER)); + Assertions.assertAll( + () -> assertThat(configuration.snapshot().resultView(), is(OftTraceResultView.TEST_RUNNER)), + () -> assertThat(configuration.snapshot().showTransitiveDefects(), is(true)) + ); } // [itest->dsn~openfasttrace-run-configuration-icon~1] @@ -170,7 +183,8 @@ public void testGivenUserRequirementsTemplateWhenCreatingConfigurationThenItHasC false, false, "doc/", - "feat, req, scn, bconstr" + "feat, req, scn, bconstr", + true ); } @@ -181,7 +195,8 @@ public void testGivenDesignAndAboveTemplateWhenCreatingConfigurationThenItHasCor false, false, "doc/", - "feat, req, scn, bconstr, arch, dsn, constr, bld" + "feat, req, scn, bconstr, arch, dsn, constr, bld", + true ); } @@ -192,7 +207,8 @@ public void testGivenTypicalProjectTemplateWhenCreatingConfigurationThenItHasCor true, true, "doc/", - "" + "", + true ); } @@ -203,17 +219,20 @@ public void testGivenUnfilteredTemplateWhenCreatingConfigurationThenItHasCorrect false, false, ".", - "" + "", + true ); } + // [itest->dsn~show-transitive-defects-by-default-in-run-configuration-templates~1] private void assertTemplateSettings( final String templateName, final boolean wholeProject, final boolean includeSourceRoots, final boolean includeTestRoots, final String additionalPathsText, - final String artifactTypesText + final String artifactTypesText, + final boolean showTransitiveDefects ) { final OftRunConfiguration configuration = createConfigurationFromTemplate(templateName); final OftTraceSettingsSnapshot snapshot = configuration.snapshot(); @@ -227,7 +246,8 @@ private void assertTemplateSettings( () -> assertThat(snapshot.additionalPathsText(), is(additionalPathsText)), () -> assertThat(snapshot.artifactTypesText(), is(artifactTypesText)), () -> assertThat(snapshot.tagsText(), is("")), - () -> assertThat(snapshot.includeUntagged(), is(false)) + () -> assertThat(snapshot.includeUntagged(), is(false)), + () -> assertThat(snapshot.showTransitiveDefects(), is(showTransitiveDefects)) ); } From 6732230fda49b466e032916dc04d78d62057143c Mon Sep 17 00:00:00 2001 From: redcatbear Date: Thu, 6 Aug 2026 21:50:53 +0200 Subject: [PATCH 04/10] #39: Filter works, but dialog has overlapping cells. --- doc/design/building_block_view.md | 6 ++- .../intellijplugin/trace/OftTraceService.java | 24 +++++++++-- .../trace/OftTraceSettingsSnapshot.java | 27 +++++++++++++ .../OftTraceTestRunnerOutputPresenter.java | 12 +++++- .../trace/OftTraceTestTreeMapper.java | 17 +++++++- .../trace/runconfig/OftRunProfileState.java | 9 ++++- .../trace/OftTraceServiceTest.java | 22 ++++++++++ ...OftTraceTestRunnerOutputPresenterTest.java | 40 ++++++++++++++++--- .../trace/OftTraceTestTreeMapperTest.java | 21 ++++++++++ 9 files changed, 165 insertions(+), 13 deletions(-) diff --git a/doc/design/building_block_view.md b/doc/design/building_block_view.md index 2029bf0..bed14cc 100644 --- a/doc/design/building_block_view.md +++ b/doc/design/building_block_view.md @@ -460,11 +460,15 @@ scale 2 Tags: | "mvp " . | (comma-separated, empty = all) . | [ ] Include untagged items + . | . + Defects | [X] Include transitive defects + } + --- + { . | . Result view: | () Plain text output . | (X) IntelliJ Test Runner UI . | . - . | [X] Include transitive defects } { diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java index 25dd089..bd07559 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java @@ -29,15 +29,29 @@ public final class OftTraceService { private final Oft oft; private final OftTraceReportRenderer reportRenderer; + private final boolean showTransitiveDefects; // [impl->dsn~trace-execution-service~1] public OftTraceService() { - this(Oft.create(), new OftPlainTextTraceReportRenderer()); + this(Oft.create(), new OftPlainTextTraceReportRenderer(), true); + } + + public OftTraceService(final boolean showTransitiveDefects) { + this(Oft.create(), new OftPlainTextTraceReportRenderer(), showTransitiveDefects); } OftTraceService(final Oft oft, final OftTraceReportRenderer reportRenderer) { + this(oft, reportRenderer, true); + } + + OftTraceService( + final Oft oft, + final OftTraceReportRenderer reportRenderer, + final boolean showTransitiveDefects + ) { this.oft = oft; this.reportRenderer = reportRenderer; + this.showTransitiveDefects = showTransitiveDefects; } // [impl->dsn~show-successful-trace-output-in-ide-output-window~2] @@ -115,10 +129,14 @@ private String renderTrace(final Trace trace) { return runWithPluginClassLoader(() -> reportRenderer.render(trace, createReportSettings())); } - private static ReportSettings createReportSettings() { + // [impl->dsn~hide-transitive-defects-in-plain-text-output~1] + // [impl->dsn~transitive-defect-visibility-is-controlled-by-the-run-configuration~1] + private ReportSettings createReportSettings() { return ReportSettings.builder() .outputFormat(ReportConstants.DEFAULT_REPORT_FORMAT) - .verbosity(ReportVerbosity.FAILURE_DETAILS) + .verbosity(showTransitiveDefects + ? ReportVerbosity.FAILURE_DETAILS + : ReportVerbosity.DIRECT_FAILURE_DETAILS) .colorScheme(ColorScheme.COLOR) .detailsSectionDisplay(DetailsSectionDisplay.COLLAPSE) .build(); diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsSnapshot.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsSnapshot.java index 349faef..3a83a40 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsSnapshot.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsSnapshot.java @@ -11,6 +11,7 @@ public record OftTraceSettingsSnapshot( String artifactTypesText, String tagsText, boolean includeUntagged, + boolean showTransitiveDefects, OftTraceResultView resultView ) { public static final OftTraceSettingsSnapshot DEFAULT = new OftTraceSettingsSnapshot( @@ -21,6 +22,7 @@ public record OftTraceSettingsSnapshot( "", "", false, + true, OftTraceResultView.TEST_RUNNER ); @@ -43,10 +45,34 @@ public OftTraceSettingsSnapshot( artifactTypesText, tagsText, false, + true, DEFAULT.resultView() ); } + public OftTraceSettingsSnapshot( + final OftTraceScopeMode scopeMode, + final boolean includeSourceRoots, + final boolean includeTestRoots, + final String additionalPathsText, + final String artifactTypesText, + final String tagsText, + final boolean includeUntagged, + final OftTraceResultView resultView + ) { + this( + scopeMode, + includeSourceRoots, + includeTestRoots, + additionalPathsText, + artifactTypesText, + tagsText, + includeUntagged, + true, + resultView + ); + } + public OftTraceSettingsSnapshot( final OftTraceScopeMode scopeMode, final boolean includeSourceRoots, @@ -64,6 +90,7 @@ public OftTraceSettingsSnapshot( artifactTypesText, tagsText, false, + true, resultView ); } diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenter.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenter.java index d32533d..7c778af 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenter.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenter.java @@ -13,9 +13,18 @@ public final class OftTraceTestRunnerOutputPresenter implements OftTraceOutputPresenter { private final Function consoleFactory; + private final boolean showTransitiveDefects; public OftTraceTestRunnerOutputPresenter(final Function consoleFactory) { + this(consoleFactory, true); + } + + public OftTraceTestRunnerOutputPresenter( + final Function consoleFactory, + final boolean showTransitiveDefects + ) { this.consoleFactory = consoleFactory; + this.showTransitiveDefects = showTransitiveDefects; } // [impl->dsn~trace-test-runner-presentation~1] @@ -29,7 +38,8 @@ public void show(final Project project, final String contentTitle, final OftTrac final PresentationOutcome outcome = result.trace() .map(trace -> showTrace(project, resultsViewer, root, OftTraceTestTreeMapper.map( trace, - project.getBasePath() + project.getBasePath(), + showTransitiveDefects ))) .orElseGet(() -> showResultWithoutTrace(console, resultsViewer, root, result)); if (outcome.failed()) { diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestTreeMapper.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestTreeMapper.java index 9f6fb2e..6fad98e 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestTreeMapper.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestTreeMapper.java @@ -59,7 +59,22 @@ static OftTraceTestTree map(final Trace trace) { } static OftTraceTestTree map(final Trace trace, final String projectBasePath) { - final List visibleLinksByItem = visibleLinksByItem(trace.getItems()); + return map(trace, projectBasePath, true); + } + + static OftTraceTestTree map( + final Trace trace, + final String projectBasePath, + final boolean showTransitiveDefects + ) { + // [impl->dsn~hide-transitive-defects-in-test-runner-ui~1] + // [impl->dsn~transitive-defect-visibility-is-controlled-by-the-run-configuration~1] + final List items = showTransitiveDefects + ? trace.getItems() + : trace.getItems().stream() + .filter(item -> !item.isTransitiveDefect()) + .toList(); + final List visibleLinksByItem = visibleLinksByItem(items); final Map itemsBySource = new LinkedHashMap<>(); for (final TraceItemLinks itemLinks : visibleLinksByItem) { final SourceFileSuite sourceFileSuite = sourceFileSuite(itemLinks.item(), projectBasePath); diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileState.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileState.java index d5fef6a..28e5c5b 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileState.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileState.java @@ -52,8 +52,10 @@ public OftRunProfileState(final ExecutionEnvironment environment, final OftTrace } final ProcessHandler processHandler = new NopProcessHandler(); + final OftTraceService traceService = new OftTraceService(settings.showTransitiveDefects()); + // [impl->dsn~transitive-defect-visibility-is-controlled-by-the-run-configuration~1] final OftTraceRunner traceRunner = new OftTraceBackgroundRunner( - new OftTraceService(), + traceService, executionPresentation.outputPresenter(), processHandler ); @@ -95,7 +97,10 @@ private ExecutionPresentation createTestRunnerExecutionPresentation( ); final SMTRunnerConsoleView console = new SMTRunnerConsoleView(properties); console.initUI(); - final OftTraceOutputPresenter outputPresenter = new OftTraceTestRunnerOutputPresenter(p -> console); + final OftTraceOutputPresenter outputPresenter = new OftTraceTestRunnerOutputPresenter( + p -> console, + settings.showTransitiveDefects() + ); return new ExecutionPresentation(console, outputPresenter); } diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java index b2b574d..1d07f18 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java @@ -161,6 +161,28 @@ void testGivenUncleanTraceChainWhenTracingThenItReportsTheExpectedDefectCountInT ); } + // [itest->dsn~hide-transitive-defects-in-plain-text-output~1] + @Test + void testGivenUncleanTraceChainWhenTracingWithoutTransitiveDefectsThenItOmitsTransitiveItemDetails( + @TempDir final Path temporaryDirectory + ) + throws IOException { + writeUncleanTraceChainProject(temporaryDirectory); + + final OftTraceResult result = new OftTraceService(false).traceProject( + OftTraceInputs.wholeProject(temporaryDirectory, List.of(), List.of()), + OftTraceProgress.NONE + ); + final String renderedOutput = stripAnsi(result.output()); + + Assertions.assertAll( + () -> assertThat(result.isSuccessful(), is(false)), + () -> assertThat(renderedOutput, Matchers.containsString("dsn~chain_design~1")), + () -> assertThat(renderedOutput, Matchers.not(Matchers.containsString("↳ Feature"))), + () -> assertThat(renderedOutput, Matchers.not(Matchers.containsString("Feature (uncovered)"))) + ); + } + @Test void testGivenRuntimeExceptionWhenTracingThenItReturnsAnErrorResult(@TempDir final Path temporaryDirectory) { final Oft oft = (Oft) Proxy.newProxyInstance( diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java index 64c4102..992fef3 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java @@ -22,6 +22,7 @@ import org.itsallcode.openfasttrace.intellijplugin.trace.runconfig.OftRunConfigurationFactory; import org.itsallcode.openfasttrace.intellijplugin.trace.runconfig.OftRunConfigurationType; import org.jspecify.annotations.NonNull; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Arrays; @@ -165,6 +166,28 @@ public void testGivenTransitiveDefectTraceResultWhenPresentedThenItPrefixesTheNo () -> assertThat(resultsViewer.getTestsRootNode().isDefect(), is(true))); } + // [itest->dsn~hide-transitive-defects-in-test-runner-ui~1] + // [itest->dsn~trace-test-runner-presentation~1] + public void testGivenTransitiveDefectTraceResultWhenTransitiveDefectsAreHiddenThenItOmitsTransitiveItems() + throws IOException { + writeUncleanTraceChainProject(Path.of(Objects.requireNonNull(getProject().getBasePath()))); + + final OftTraceResult result = new OftTraceService(false).traceProject( + OftTraceInputs.wholeProject(Path.of(Objects.requireNonNull(getProject().getBasePath())), List.of(), List.of()), + OftTraceProgress.NONE + ); + final SMTRunnerConsoleView console = present(result, false); + final SMTestRunnerResultsForm resultsViewer = console.getResultsViewer(); + final SMTestProxy suite = resultsViewer.getTestsRootNode().getChildren().getFirst(); + + assertAll( + () -> assertThat(suite.getChildren(), hasSize(1)), + () -> assertThat(suite.getChildren().getFirst().getName(), is("Design (uncovered)")), + () -> assertThat(suite.getChildren().getFirst().isDefect(), is(true)), + () -> assertThat(resultsViewer.getTestsRootNode().isDefect(), is(true)) + ); + } + public void testGivenResultWithoutStructuredTraceWhenPresentedThenItCreatesFailedFallbackNode() { final SMTRunnerConsoleView console = present(OftTraceResult.invalidInput("invalid configuration")); final SMTestRunnerResultsForm resultsViewer = console.getResultsViewer(); @@ -186,12 +209,19 @@ public void testGivenResultWithoutStructuredTraceWhenPresentedThenItCreatesFaile } private SMTRunnerConsoleView present(final OftTraceResult result) { + return present(result, true); + } + + private SMTRunnerConsoleView present(final OftTraceResult result, final boolean showTransitiveDefects) { final AtomicReference consoleRef = new AtomicReference<>(); - final OftTraceTestRunnerOutputPresenter presenter = new OftTraceTestRunnerOutputPresenter(project -> { - final SMTRunnerConsoleView console = createConsole(); - consoleRef.set(console); - return console; - }); + final OftTraceTestRunnerOutputPresenter presenter = new OftTraceTestRunnerOutputPresenter( + project -> { + final SMTRunnerConsoleView console = createConsole(); + consoleRef.set(console); + return console; + }, + showTransitiveDefects + ); EdtTestUtil.runInEdtAndWait(() -> presenter.show( getProject(), diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestTreeMapperTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestTreeMapperTest.java index b908579..7d1af3e 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestTreeMapperTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestTreeMapperTest.java @@ -318,6 +318,27 @@ void testGivenTransitiveDefectsWhenMappingThenItPrefixesTheirNodeNames(@TempDir ); } + // [itest->dsn~hide-transitive-defects-in-test-runner-ui~1] + // [itest->dsn~trace-test-runner-presentation~1] + @Test + void testGivenTransitiveDefectsWhenMappingWithHiddenTransitivesThenItOmitsThem(@TempDir final Path temporaryDirectory) + throws IOException { + writeUncleanTraceChainProject(temporaryDirectory); + + final Trace trace = new OftTraceService().traceProject( + OftTraceInputs.wholeProject(temporaryDirectory, List.of(), List.of()), + OftTraceProgress.NONE + ).trace().orElseThrow(); + final OftTraceTestTree tree = OftTraceTestTreeMapper.map(trace, null, false); + final OftTraceSuiteNode suite = tree.suites().getFirst(); + + Assertions.assertAll( + () -> assertThat(suite.items(), hasSize(1)), + () -> assertThat(suite.items().getFirst().name(), is("Design (uncovered)")), + () -> assertThat(tree.failed(), is(true)) + ); + } + // [itest->dsn~trace-test-runner-presentation~1] // [itest->dsn~show-specification-item-status-in-test-runner-ui~2] // [itest->dsn~map-specification-item-trace-status-to-test-runner-status~1] From dc96f33fbcc1646dca452ab70247b4d7e885eb64 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Fri, 7 Aug 2026 13:18:22 +0200 Subject: [PATCH 05/10] #39: Filter dialog looks good. --- doc/design/building_block_view.md | 2 + .../trace/OftTraceSettingsComponent.java | 231 +++++++++++++++--- 2 files changed, 199 insertions(+), 34 deletions(-) diff --git a/doc/design/building_block_view.md b/doc/design/building_block_view.md index bed14cc..2381c8d 100644 --- a/doc/design/building_block_view.md +++ b/doc/design/building_block_view.md @@ -478,3 +478,5 @@ scale 2 } @endsalt ``` + +The filter area uses a hierarchical layout: section headers introduce the group, each filter row keeps its label in the first column and its input in the second column, and the helper text or checkbox rows align underneath the corresponding input. If that arrangement needs another adjustment later, the next iteration should refine the existing hierarchy and row constraints instead of restarting the dialog layout from zero. diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java index b0646d8..1ebb5b8 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java @@ -7,15 +7,16 @@ import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBTextArea; import com.intellij.ui.components.JBTextField; -import com.intellij.util.ui.FormBuilder; -import javax.swing.ButtonGroup; -import javax.swing.JComponent; -import javax.swing.JPanel; +import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.BorderLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; import java.awt.Dimension; +import java.awt.Font; +import java.awt.Insets; import java.nio.file.Path; public final class OftTraceSettingsComponent { @@ -32,6 +33,8 @@ public final class OftTraceSettingsComponent { private final JBTextField tagsField = new JBTextField(); private final JBCheckBox includeUntaggedCheckBox = new JBCheckBox("Include untagged items"); + private final JBCheckBox showTransitiveDefectsCheckBox = + new JBCheckBox("Show transitive defects"); private final JBRadioButton plainTextResultViewRadioButton = new JBRadioButton("Plain text output"); private final JBRadioButton testRunnerResultViewRadioButton = @@ -83,38 +86,40 @@ public void changedUpdate(final DocumentEvent event) { validationMessagesArea.setWrapStyleWord(true); final JComponent scrollPane = new JBScrollPane(additionalPathsTextArea); scrollPane.setPreferredSize(new Dimension(420, 110)); - final JBPanel additionalPathsPanel = new JBPanel<>(new BorderLayout(0, 4)); - additionalPathsPanel.add( - new JBLabel("Additional project-relative files or directories (one per line)"), - BorderLayout.NORTH - ); - additionalPathsPanel.add(scrollPane, BorderLayout.CENTER); - final JBPanel additionalPathsFeedbackPanel = new JBPanel<>(new BorderLayout(0, 4)); - additionalPathsFeedbackPanel.add(resolvedRelativeToLabel, BorderLayout.NORTH); - additionalPathsFeedbackPanel.add(validationMessagesArea, BorderLayout.CENTER); - additionalPathsPanel.add(additionalPathsFeedbackPanel, BorderLayout.SOUTH); - final FormBuilder formBuilder = FormBuilder.createFormBuilder() - .addComponent(wholeProjectRadioButton) - .addComponent(selectedResourcesRadioButton) - .addComponent(includeSourceRootsCheckBox, 1) - .addComponent(includeTestRootsCheckBox, 1) - .addComponent(additionalPathsPanel, 1) - .addSeparator() - .addLabeledComponent("Artifact types:", artifactTypesField) - .addTooltip("comma-separated, empty = all") - .addLabeledComponent("Tags:", tagsField) - .addTooltip("comma-separated, empty = all") - .addLabeledComponent("", includeUntaggedCheckBox); + final JBPanel bodyPanel = new JBPanel<>(); + bodyPanel.setLayout(new GridBagLayout()); + final GridBagConstraints bodyConstraints = new GridBagConstraints(); + bodyConstraints.gridx = 0; + bodyConstraints.weightx = 1.0; + bodyConstraints.fill = GridBagConstraints.HORIZONTAL; + bodyConstraints.anchor = GridBagConstraints.WEST; + bodyConstraints.insets = new Insets(0, 0, 0, 0); + + int row = 0; + row = addSectionHeader(bodyPanel, bodyConstraints, row, "Trace Scope"); + row = addTopRow(bodyPanel, bodyConstraints, row, wholeProjectRadioButton); + row = addTopRow(bodyPanel, bodyConstraints, row, selectedResourcesRadioButton); + row = addIndentedRow(bodyPanel, bodyConstraints, row, includeSourceRootsCheckBox); + row = addIndentedRow(bodyPanel, bodyConstraints, row, includeTestRootsCheckBox); + row = addAdditionalPathsBlock(bodyPanel, bodyConstraints, row, scrollPane); + + row = addSectionSeparator(bodyPanel, bodyConstraints, row); + row = addSectionHeader(bodyPanel, bodyConstraints, row, "Filters"); + row = addFilterRow(bodyPanel, bodyConstraints, row, "Artifact types:", artifactTypesField); + row = addHelpRow(bodyPanel, bodyConstraints, row, "comma-separated, empty = all"); + row = addFilterRow(bodyPanel, bodyConstraints, row, "Tags:", tagsField); + row = addHelpRow(bodyPanel, bodyConstraints, row, "comma-separated, empty = all"); + row = addCheckboxRow(bodyPanel, bodyConstraints, row, includeUntaggedCheckBox); + row = addCheckboxRow(bodyPanel, bodyConstraints, row, showTransitiveDefectsCheckBox); if (showResultViewSelection) { - formBuilder - .addSeparator() - .addComponent(new JBLabel("Result view")) - .addComponent(plainTextResultViewRadioButton, 1) - .addComponent(testRunnerResultViewRadioButton, 1); + row = addSectionSeparator(bodyPanel, bodyConstraints, row); + row = addSectionHeader(bodyPanel, bodyConstraints, row, "Result view"); + row = addIndentedRow(bodyPanel, bodyConstraints, row, plainTextResultViewRadioButton); + row = addIndentedRow(bodyPanel, bodyConstraints, row, testRunnerResultViewRadioButton); } - panel = formBuilder - .addComponentFillVertically(new JPanel(), 0) - .getPanel(); + + panel = new JBPanel<>(new BorderLayout()); + panel.add(bodyPanel, BorderLayout.NORTH); setSettings(OftTraceSettingsSnapshot.DEFAULT); } @@ -133,6 +138,7 @@ public OftTraceSettingsSnapshot getSettings() { artifactTypesField.getText(), tagsField.getText(), includeUntaggedCheckBox.isSelected(), + showTransitiveDefectsCheckBox.isSelected(), selectedResultView() ); } @@ -146,6 +152,7 @@ public void setSettings(final OftTraceSettingsSnapshot settings) { artifactTypesField.setText(settings.artifactTypesText()); tagsField.setText(settings.tagsText()); includeUntaggedCheckBox.setSelected(settings.includeUntagged()); + showTransitiveDefectsCheckBox.setSelected(settings.showTransitiveDefects()); plainTextResultViewRadioButton.setSelected(settings.resultView() == OftTraceResultView.PLAIN_TEXT); testRunnerResultViewRadioButton.setSelected(settings.resultView() == OftTraceResultView.TEST_RUNNER); updateSelectedResourcesEnabledState(); @@ -190,11 +197,167 @@ private void updateValidationFeedback() { if (!selectedResourcesRadioButton.isSelected() || projectRoot == null) { resolvedRelativeToLabel.setText(""); validationMessagesArea.setText(""); + resolvedRelativeToLabel.setVisible(false); + validationMessagesArea.setVisible(false); return; } final OftAdditionalTracePathValidation validation = OftAdditionalTracePathValidation.validate(projectRoot, additionalPathsTextArea.getText()); resolvedRelativeToLabel.setText(validation.resolvedRelativeToText()); validationMessagesArea.setText(String.join(System.lineSeparator(), validation.messages())); + resolvedRelativeToLabel.setVisible(!resolvedRelativeToLabel.getText().isEmpty()); + validationMessagesArea.setVisible(!validationMessagesArea.getText().isEmpty()); + } + + private static int addTopRow( + final JBPanel panel, + final GridBagConstraints constraints, + final int row, + final JComponent component + ) { + constraints.gridy = row; + constraints.gridx = 0; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1.0; + constraints.insets = new Insets(row == 0 ? 0 : 4, 0, 0, 0); + panel.add(component, constraints); + return row + 1; + } + + private static int addIndentedRow( + final JBPanel panel, + final GridBagConstraints constraints, + final int row, + final JComponent component + ) { + constraints.gridy = row; + constraints.gridx = 0; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1.0; + constraints.insets = new Insets(4, 18, 0, 0); + panel.add(component, constraints); + return row + 1; + } + + private int addAdditionalPathsBlock( + final JBPanel panel, + final GridBagConstraints constraints, + final int row, + final JComponent scrollPane + ) { + constraints.gridy = row; + constraints.gridx = 0; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1.0; + constraints.insets = new Insets(8, 0, 0, 0); + + final JBPanel additionalPathsPanel = new JBPanel<>(new BorderLayout(0, 4)); + additionalPathsPanel.add( + new JBLabel("Additional project-relative files or directories (one per line)"), + BorderLayout.NORTH + ); + + final JBPanel validationPanel = new JBPanel<>(new BorderLayout(0, 2)); + validationPanel.add(resolvedRelativeToLabel, BorderLayout.NORTH); + validationPanel.add(validationMessagesArea, BorderLayout.CENTER); + + final JBPanel contentPanel = new JBPanel<>(new BorderLayout(0, 4)); + contentPanel.add(scrollPane, BorderLayout.CENTER); + contentPanel.add(validationPanel, BorderLayout.SOUTH); + + additionalPathsPanel.add(contentPanel, BorderLayout.CENTER); + panel.add(additionalPathsPanel, constraints); + return row + 1; + } + + private int addFilterRow( + final JBPanel panel, + final GridBagConstraints constraints, + final int row, + final String label, + final JComponent field + ) { + constraints.gridy = row; + constraints.gridx = 0; + constraints.gridwidth = 1; + constraints.weightx = 0.0; + constraints.insets = new Insets(row == 0 ? 0 : 8, 0, 0, 8); + panel.add(new JBLabel(label), constraints); + + constraints.gridx = 1; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1.0; + constraints.insets = new Insets(row == 0 ? 0 : 8, 0, 0, 0); + panel.add(field, constraints); + return row + 1; + } + + private int addHelpRow( + final JBPanel panel, + final GridBagConstraints constraints, + final int row, + final String text + ) { + constraints.gridy = row; + constraints.gridx = 1; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1.0; + constraints.insets = new Insets(4, 0, 0, 0); + final JBLabel helpLabel = new JBLabel(text); + helpLabel.setFont(helpLabel.getFont().deriveFont(helpLabel.getFont().getSize2D() - 1.0f)); + helpLabel.setForeground(helpLabel.getForeground().darker()); + panel.add(helpLabel, constraints); + return row + 1; + } + + private int addCheckboxRow( + final JBPanel panel, + final GridBagConstraints constraints, + final int row, + final JComponent component + ) { + constraints.gridy = row; + constraints.gridx = 1; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1.0; + constraints.insets = new Insets(4, 0, 0, 0); + panel.add(component, constraints); + return row + 1; + } + + private int addSectionSeparator( + final JBPanel panel, + final GridBagConstraints constraints, + final int row + ) { + constraints.gridy = row; + constraints.gridx = 0; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1.0; + constraints.insets = new Insets(12, 0, 8, 0); + panel.add(createSeparator(), constraints); + return row + 1; + } + + private int addSectionHeader( + final JBPanel panel, + final GridBagConstraints constraints, + final int row, + final String text + ) { + constraints.gridy = row; + constraints.gridx = 0; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1.0; + constraints.insets = new Insets(0, 0, 2, 0); + final JBLabel label = new JBLabel(text); + final Font font = label.getFont(); + label.setFont(font.deriveFont(Font.BOLD, font.getSize2D())); + panel.add(label, constraints); + return row + 1; + } + + private static JComponent createSeparator() { + return new JSeparator(SwingConstants.HORIZONTAL); } } From ee023735cdb1a7e86c482ea5e3ab3fcb45eb8428 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Fri, 7 Aug 2026 13:47:29 +0200 Subject: [PATCH 06/10] #39: Filter dialog layout clean. --- .../trace/OftTraceSettingsComponent.java | 93 +++++++------------ 1 file changed, 31 insertions(+), 62 deletions(-) diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java index 1ebb5b8..4d8cfea 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java @@ -38,17 +38,13 @@ public final class OftTraceSettingsComponent { private final JBRadioButton plainTextResultViewRadioButton = new JBRadioButton("Plain text output"); private final JBRadioButton testRunnerResultViewRadioButton = - new JBRadioButton("IntelliJ Test Runner UI"); + new JBRadioButton("IntelliJ test runner UI"); private final JBLabel resolvedRelativeToLabel = new JBLabel(); private final JBTextArea validationMessagesArea = new JBTextArea(); private final Path projectRoot; private final boolean showResultViewSelection; private final JPanel panel; - public OftTraceSettingsComponent(final Path projectRoot) { - this(projectRoot, false); - } - public OftTraceSettingsComponent(final Path projectRoot, final boolean showResultViewSelection) { this.projectRoot = projectRoot; this.showResultViewSelection = showResultViewSelection; @@ -97,25 +93,25 @@ public void changedUpdate(final DocumentEvent event) { int row = 0; row = addSectionHeader(bodyPanel, bodyConstraints, row, "Trace Scope"); - row = addTopRow(bodyPanel, bodyConstraints, row, wholeProjectRadioButton); - row = addTopRow(bodyPanel, bodyConstraints, row, selectedResourcesRadioButton); - row = addIndentedRow(bodyPanel, bodyConstraints, row, includeSourceRootsCheckBox); - row = addIndentedRow(bodyPanel, bodyConstraints, row, includeTestRootsCheckBox); + row = addComponentRow(bodyPanel, bodyConstraints, row, wholeProjectRadioButton, 0, 0); + row = addComponentRow(bodyPanel, bodyConstraints, row, selectedResourcesRadioButton, 4, 0); + row = addComponentRow(bodyPanel, bodyConstraints, row, includeSourceRootsCheckBox, 4, 18); + row = addComponentRow(bodyPanel, bodyConstraints, row, includeTestRootsCheckBox, 4, 18); row = addAdditionalPathsBlock(bodyPanel, bodyConstraints, row, scrollPane); row = addSectionSeparator(bodyPanel, bodyConstraints, row); row = addSectionHeader(bodyPanel, bodyConstraints, row, "Filters"); - row = addFilterRow(bodyPanel, bodyConstraints, row, "Artifact types:", artifactTypesField); + row = addLabeledComponentRow(bodyPanel, bodyConstraints, row, "Artifact types:", artifactTypesField, 8); row = addHelpRow(bodyPanel, bodyConstraints, row, "comma-separated, empty = all"); - row = addFilterRow(bodyPanel, bodyConstraints, row, "Tags:", tagsField); + row = addLabeledComponentRow(bodyPanel, bodyConstraints, row, "Tags:", tagsField, 8); row = addHelpRow(bodyPanel, bodyConstraints, row, "comma-separated, empty = all"); - row = addCheckboxRow(bodyPanel, bodyConstraints, row, includeUntaggedCheckBox); - row = addCheckboxRow(bodyPanel, bodyConstraints, row, showTransitiveDefectsCheckBox); + row = addIndentedComponentRow(bodyPanel, bodyConstraints, row, includeUntaggedCheckBox, 4); + row = addLabeledComponentRow(bodyPanel, bodyConstraints, row, "Defects:", showTransitiveDefectsCheckBox, 4); if (showResultViewSelection) { row = addSectionSeparator(bodyPanel, bodyConstraints, row); row = addSectionHeader(bodyPanel, bodyConstraints, row, "Result view"); - row = addIndentedRow(bodyPanel, bodyConstraints, row, plainTextResultViewRadioButton); - row = addIndentedRow(bodyPanel, bodyConstraints, row, testRunnerResultViewRadioButton); + row = addComponentRow(bodyPanel, bodyConstraints, row, plainTextResultViewRadioButton, 4, 18); + addComponentRow(bodyPanel, bodyConstraints, row, testRunnerResultViewRadioButton, 4, 18); } panel = new JBPanel<>(new BorderLayout()); @@ -158,16 +154,6 @@ public void setSettings(final OftTraceSettingsSnapshot settings) { updateSelectedResourcesEnabledState(); } - public boolean isSelectedResourcesEnabled() { - return includeSourceRootsCheckBox.isEnabled() - && includeTestRootsCheckBox.isEnabled() - && additionalPathsTextArea.isEnabled(); - } - - public String resolvedRelativeToText() { - return resolvedRelativeToLabel.getText(); - } - public String validationMessagesText() { return validationMessagesArea.getText(); } @@ -209,32 +195,19 @@ private void updateValidationFeedback() { validationMessagesArea.setVisible(!validationMessagesArea.getText().isEmpty()); } - private static int addTopRow( + private static int addComponentRow( final JBPanel panel, final GridBagConstraints constraints, final int row, - final JComponent component + final JComponent component, + final int topInset, + final int leftInset ) { constraints.gridy = row; constraints.gridx = 0; constraints.gridwidth = GridBagConstraints.REMAINDER; constraints.weightx = 1.0; - constraints.insets = new Insets(row == 0 ? 0 : 4, 0, 0, 0); - panel.add(component, constraints); - return row + 1; - } - - private static int addIndentedRow( - final JBPanel panel, - final GridBagConstraints constraints, - final int row, - final JComponent component - ) { - constraints.gridy = row; - constraints.gridx = 0; - constraints.gridwidth = GridBagConstraints.REMAINDER; - constraints.weightx = 1.0; - constraints.insets = new Insets(4, 18, 0, 0); + constraints.insets = new Insets(topInset, leftInset, 0, 0); panel.add(component, constraints); return row + 1; } @@ -270,58 +243,54 @@ private int addAdditionalPathsBlock( return row + 1; } - private int addFilterRow( + private int addLabeledComponentRow( final JBPanel panel, final GridBagConstraints constraints, final int row, final String label, - final JComponent field + final JComponent field, + final int topInset ) { constraints.gridy = row; constraints.gridx = 0; constraints.gridwidth = 1; constraints.weightx = 0.0; - constraints.insets = new Insets(row == 0 ? 0 : 8, 0, 0, 8); + constraints.insets = new Insets(topInset, 0, 0, 8); panel.add(new JBLabel(label), constraints); constraints.gridx = 1; constraints.gridwidth = GridBagConstraints.REMAINDER; constraints.weightx = 1.0; - constraints.insets = new Insets(row == 0 ? 0 : 8, 0, 0, 0); + constraints.insets = new Insets(topInset, 0, 0, 0); panel.add(field, constraints); return row + 1; } - private int addHelpRow( + private int addIndentedComponentRow( final JBPanel panel, final GridBagConstraints constraints, final int row, - final String text + final JComponent component, + final int topInset ) { - constraints.gridy = row; - constraints.gridx = 1; - constraints.gridwidth = GridBagConstraints.REMAINDER; - constraints.weightx = 1.0; - constraints.insets = new Insets(4, 0, 0, 0); - final JBLabel helpLabel = new JBLabel(text); - helpLabel.setFont(helpLabel.getFont().deriveFont(helpLabel.getFont().getSize2D() - 1.0f)); - helpLabel.setForeground(helpLabel.getForeground().darker()); - panel.add(helpLabel, constraints); - return row + 1; + return addLabeledComponentRow(panel, constraints, row, "", component, topInset); } - private int addCheckboxRow( + private int addHelpRow( final JBPanel panel, final GridBagConstraints constraints, final int row, - final JComponent component + final String text ) { constraints.gridy = row; constraints.gridx = 1; constraints.gridwidth = GridBagConstraints.REMAINDER; constraints.weightx = 1.0; constraints.insets = new Insets(4, 0, 0, 0); - panel.add(component, constraints); + final JBLabel helpLabel = new JBLabel(text); + helpLabel.setFont(helpLabel.getFont().deriveFont(helpLabel.getFont().getSize2D() - 1.0f)); + helpLabel.setForeground(helpLabel.getForeground().darker()); + panel.add(helpLabel, constraints); return row + 1; } From 76354e858880aa1c73fac39d94528db5d0b1b5e4 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Fri, 7 Aug 2026 13:55:12 +0200 Subject: [PATCH 07/10] #72: Updated changelog. --- doc/changes/changes_0.10.0.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changes/changes_0.10.0.md b/doc/changes/changes_0.10.0.md index 6b1a8f9..f04189b 100644 --- a/doc/changes/changes_0.10.0.md +++ b/doc/changes/changes_0.10.0.md @@ -1,8 +1,11 @@ # OpenFastTrace IntelliJ Plugin 0.10.0, released 2026-07-04 We also updated the bundled OFT to 4.8.0 so tag filters now work end to end instead of being ignored. + The Test Runner UI now marks transitive defects with a leading `↳` so they stand out from direct defects in the result tree. +The run configuration now allows filtering out transitive defects. + ## Bundled OpenFastTrace OpenFastTrace 4.8.0 @@ -10,6 +13,7 @@ OpenFastTrace 4.8.0 ## Feature * #66: Transitive defects now use a visible `↳` prefix in the Test Runner UI +* #72: Filter for transitive defects in the run configuration ## Bugfix From b7e626f92595a244f3970db64bae297eee62ba0b Mon Sep 17 00:00:00 2001 From: redcatbear Date: Fri, 7 Aug 2026 17:08:48 +0200 Subject: [PATCH 08/10] #72: Fixed Sonar findings. --- .../trace/OftTraceSettingsComponent.java | 10 +++++----- .../trace/OftTraceTestRunnerOutputPresenterTest.java | 4 +--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java index 4d8cfea..82e1dfb 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java @@ -243,7 +243,7 @@ private int addAdditionalPathsBlock( return row + 1; } - private int addLabeledComponentRow( + private static int addLabeledComponentRow( final JBPanel panel, final GridBagConstraints constraints, final int row, @@ -266,7 +266,7 @@ private int addLabeledComponentRow( return row + 1; } - private int addIndentedComponentRow( + private static int addIndentedComponentRow( final JBPanel panel, final GridBagConstraints constraints, final int row, @@ -276,7 +276,7 @@ private int addIndentedComponentRow( return addLabeledComponentRow(panel, constraints, row, "", component, topInset); } - private int addHelpRow( + private static int addHelpRow( final JBPanel panel, final GridBagConstraints constraints, final int row, @@ -294,7 +294,7 @@ private int addHelpRow( return row + 1; } - private int addSectionSeparator( + private static int addSectionSeparator( final JBPanel panel, final GridBagConstraints constraints, final int row @@ -308,7 +308,7 @@ private int addSectionSeparator( return row + 1; } - private int addSectionHeader( + private static int addSectionHeader( final JBPanel panel, final GridBagConstraints constraints, final int row, diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java index 992fef3..1affa7b 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java @@ -22,8 +22,6 @@ import org.itsallcode.openfasttrace.intellijplugin.trace.runconfig.OftRunConfigurationFactory; import org.itsallcode.openfasttrace.intellijplugin.trace.runconfig.OftRunConfigurationType; import org.jspecify.annotations.NonNull; -import org.junit.jupiter.api.Test; - import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -269,7 +267,7 @@ private static String ownOutput(final SMTestProxy proxy) { final StringBuilder output = new StringBuilder(); proxy.printOwnPrintablesOn(new Printer() { @Override - public void print(final @NonNull String text, final ConsoleViewContentType contentType) { + public void print(final @NonNull String text, final @NonNull ConsoleViewContentType contentType) { output.append(text); } From d344599236443b2e91283af7095d1c9b98d1198c Mon Sep 17 00:00:00 2001 From: redcatbear Date: Fri, 7 Aug 2026 17:17:34 +0200 Subject: [PATCH 09/10] #72: Replaced interal API. --- ...OftTraceTestRunnerOutputPresenterTest.java | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java index 1affa7b..3b816db 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceTestRunnerOutputPresenterTest.java @@ -72,8 +72,8 @@ public void testGivenSuccessfulTraceResultWhenPresentedThenItCreatesPassedTestRu assertThat(ownOutput(item), containsString("Trace status: covered")); assertThat(suite.isDefect(), is(false)); assertThat(resultsViewer.getTestsRootNode().isDefect(), is(false)); - assertThat(resultsViewer.getTotalTestCount(), is(1)); - assertThat(resultsViewer.getFailedTestCount(), is(0)); + assertThat(totalTestCount(resultsViewer), is(1)); + assertThat(failedTestCount(resultsViewer), is(0)); } // [itest->dsn~show-trace-source-files-as-test-runner-suites~1] @@ -127,8 +127,8 @@ public void testGivenDefectiveTraceResultWhenPresentedThenItCreatesFailedItemAnd assertThat(link.getStacktrace(), containsString("Owning item ID: impl~missing_requirement~1")); assertThat(link.getStacktrace(), containsString("Linked item ID: req~missing_requirement~1")); assertThat(link.getStacktrace(), containsString("OpenFastTrace could not find")); - assertThat(resultsViewer.getTotalTestCount(), is(2)); - assertThat(resultsViewer.getFailedTestCount(), is(2)); + assertThat(totalTestCount(resultsViewer), is(2)); + assertThat(failedTestCount(resultsViewer), is(2)); } // [itest->dsn~mark-transitive-defects-in-test-runner~1] @@ -202,8 +202,8 @@ public void testGivenResultWithoutStructuredTraceWhenPresentedThenItCreatesFaile assertThat(fallbackNode.getStacktrace(), is("invalid configuration")); assertThat(resultsViewer.getTestsRootNode().getErrorMessage(), is("OpenFastTrace trace could not start.")); assertThat(resultsViewer.getTestsRootNode().getStacktrace(), is("invalid configuration")); - assertThat(resultsViewer.getTotalTestCount(), is(1)); - assertThat(resultsViewer.getFailedTestCount(), is(1)); + assertThat(totalTestCount(resultsViewer), is(1)); + assertThat(failedTestCount(resultsViewer), is(1)); } private SMTRunnerConsoleView present(final OftTraceResult result) { @@ -263,6 +263,24 @@ private static SMTestProxy childNamed(final SMTestProxy parent, final String nam return matchingChildren.getFirst(); } + private static int totalTestCount(final SMTestRunnerResultsForm resultsViewer) { + return nodesForTest(resultsViewer).size(); + } + + private static int failedTestCount(final SMTestRunnerResultsForm resultsViewer) { + return Math.toIntExact(nodesForTest(resultsViewer).stream() + .filter(SMTestProxy::isDefect) + .count()); + } + + private static List nodesForTest(final SMTestRunnerResultsForm resultsViewer) { + final SMTestProxy root = resultsViewer.getTestsRootNode(); + return root.getAllTests().stream() + .filter(test -> test != root) + .filter(test -> test.getParent() != root || !test.isSuite()) + .toList(); + } + private static String ownOutput(final SMTestProxy proxy) { final StringBuilder output = new StringBuilder(); proxy.printOwnPrintablesOn(new Printer() { From e7572385d63914bd657f5520d486e5e18df5e34f Mon Sep 17 00:00:00 2001 From: redcatbear Date: Fri, 7 Aug 2026 17:22:02 +0200 Subject: [PATCH 10/10] #72: Replaced interal API. --- .../intellijplugin/trace/OftTraceSettingsComponent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java index 82e1dfb..ff0c5d3 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java @@ -276,6 +276,7 @@ private static int addIndentedComponentRow( return addLabeledComponentRow(panel, constraints, row, "", component, topInset); } + @SuppressWarnings("java:S2164") // Float calculation acceptable here. private static int addHelpRow( final JBPanel panel, final GridBagConstraints constraints, @@ -288,7 +289,7 @@ private static int addHelpRow( constraints.weightx = 1.0; constraints.insets = new Insets(4, 0, 0, 0); final JBLabel helpLabel = new JBLabel(text); - helpLabel.setFont(helpLabel.getFont().deriveFont(helpLabel.getFont().getSize2D() - 1.0f)); + helpLabel.setFont(helpLabel.getFont().deriveFont(helpLabel.getFont().getSize2D() - 1.0F)); helpLabel.setForeground(helpLabel.getForeground().darker()); panel.add(helpLabel, constraints); return row + 1;