Skip to content

Commit d0f3e51

Browse files
authored
Merge pull request #468 from TESTARtool/master_verdicts
Refactor Verdict getVerdict to List<Verdict> getVerdicts
2 parents 0603bd4 + c420fd4 commit d0f3e51

100 files changed

Lines changed: 2126 additions & 1330 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test-windows-webdriver.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ jobs:
4949
name: Java${{ matrix.java }}-runTestWebdriverSuspiciousTagStateModel-artifact
5050
path: D:/a/TESTAR_dev/TESTAR_dev/testar/target/install/testar/bin/webdriver_and_suspicious
5151

52-
- name: Run webdriver to detect a browser console error in parabank
53-
run: ./gradlew runTestWebdriverParabankConsoleError
54-
- name: Save runTestWebdriverParabankConsoleError HTML report artifact
52+
- name: Run webdriver to detect a browser console error and accessibility warning in parabank
53+
run: ./gradlew runTestWebdriverParabankConsoleErrorAndAccessibilityWarning
54+
- name: Save runTestWebdriverParabankConsoleErrorAndAccessibilityWarning HTML report artifact
5555
uses: actions/upload-artifact@v4
5656
# Only upload GitHub Actions results if this task fails (Can be replaced with 'if: always()')
5757
if: failure()
5858
with:
59-
name: Java${{ matrix.java }}-runTestWebdriverParabankConsoleError-artifact
60-
path: D:/a/TESTAR_dev/TESTAR_dev/testar/target/install/testar/bin/webdriver_console_error
59+
name: Java${{ matrix.java }}-runTestWebdriverParabankConsoleErrorAndAccessibilityWarning-artifact
60+
path: D:/a/TESTAR_dev/TESTAR_dev/testar/target/install/testar/bin/webdriver_console_error_and_accessibility_warning
6161

6262
- name: Run webdriver to login in parabank and detect a welcome suspicious tag
6363
run: ./gradlew runTestWebdriverParabankLogin

CHANGELOG

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
#TESTAR v2.8.1 (9-Mar-2026)
2+
- Refactor TESTAR internals from a single Verdict getVerdict to List<Verdict> getVerdicts
3+
- Report all Verdict issues per state independently
4+
- Remove Verdict join logic
5+
- Add a feature and a setting to ignore previously detected Verdicts
6+
- Remove old disabled Record mode code
7+
- Move ExtendedOracles logic to DefaultProtocol
8+
- Remove reflective process-listener handle
9+
- Fix ExtendedSettingsFile default value
10+
- Update widget-element description logic
11+
12+
113
#TESTAR v2.7.23 (5-Mar-2026)
214
- Update webdriver remote actions descriptions
315
- Add webdriver remote actions to LLM conversation

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ Some of the most interesting parameters that can help to integrate TESTAR as an
110110

111111
ShowVisualSettingsDialogOnStartup -> To run TESTAR without the GUI
112112

113-
Mode -> TESTAR execution Mode (Spy, Generate, Record, Replay, View)
113+
Mode -> TESTAR execution Mode (Spy, Generate, Replay, View)
114114

115115
SUTConnector & SUTConnectorValue -> The way to link with the desired application to be tested
116116

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.7.23
1+
2.8.1

core/src/org/testar/ProtocolUtil.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/***************************************************************************************************
22
*
3-
* Copyright (c) 2016 - 2025 Universitat Politecnica de Valencia - www.upv.es
4-
* Copyright (c) 2019 - 2025 Open Universiteit - www.ou.nl
3+
* Copyright (c) 2016 - 2026 Universitat Politecnica de Valencia - www.upv.es
4+
* Copyright (c) 2019 - 2026 Open Universiteit - www.ou.nl
55
*
66
* Redistribution and use in source and binary forms, with or without
77
* modification, are permitted provided that the following conditions are met:
@@ -49,6 +49,7 @@
4949
import org.testar.monkey.alayer.Widget;
5050

5151
import java.awt.*;
52+
import java.util.Collections;
5253
import java.util.Iterator;
5354
import java.util.LinkedHashMap;
5455
import java.util.List;
@@ -251,7 +252,8 @@ public static AWTCanvas getStateshotBinary(State state) {
251252
}
252253

253254
//If the state Shape is not properly obtained, or the State has an error, use full monitor screen
254-
if (viewPort == null || (state.get(Tags.OracleVerdict, Verdict.OK).severity() > Verdict.Severity.OK.getValue()))
255+
List<Verdict> verdicts = state.get(Tags.OracleVerdicts, Collections.singletonList(Verdict.OK));
256+
if (viewPort == null || !Verdict.helperAreAllVerdictsOK(verdicts))
255257
viewPort = state.get(Tags.Shape, null); // get the SUT process canvas (usually, full monitor screen)
256258

257259
// Validate viewport dimensions before taking the screenshot

core/src/org/testar/monkey/alayer/Tags.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/***************************************************************************************************
22
*
3-
* Copyright (c) 2013 - 2025 Universitat Politecnica de Valencia - www.upv.es
4-
* Copyright (c) 2018 - 2025 Open Universiteit - www.ou.nl
3+
* Copyright (c) 2013 - 2026 Universitat Politecnica de Valencia - www.upv.es
4+
* Copyright (c) 2018 - 2026 Open Universiteit - www.ou.nl
55
*
66
* Redistribution and use in source and binary forms, with or without
77
* modification, are permitted provided that the following conditions are met:
@@ -28,10 +28,6 @@
2828
* POSSIBILITY OF SUCH DAMAGE.
2929
*******************************************************************************************************/
3030

31-
/**
32-
* @author Sebastian Bauersfeld
33-
*/
34-
3531
package org.testar.monkey.alayer;
3632

3733
import org.testar.CodingManager;
@@ -161,9 +157,9 @@ private Tags() {}
161157
/** Usually attached to an object of {@link State}. The value is a screenshot of the state. */
162158
public static final Tag<String> ScreenshotPath = from("ScreenshotPath", String.class);
163159

164-
/** Usually attached to a {@link State} object. The value is an outcome of a test oracle for that state. It is
165-
* used to mark states as 'suspicious' or 'erroneous' */
166-
public static final Tag<Verdict> OracleVerdict = from("OracleVerdict", Verdict.class);
160+
/** Usually attached to a {@link State} object. The value is a list of outcomes of test oracles for that state. */
161+
@SuppressWarnings("unchecked")
162+
public static final Tag<List<Verdict>> OracleVerdicts = from("OracleVerdicts", (Class<List<Verdict>>)(Class<?>)List.class);
167163

168164
/** The standard mouse object. Usually attached to systems */
169165
public static final Tag<Mouse> StandardMouse = from("StandardMouse", Mouse.class);

core/src/org/testar/monkey/alayer/Verdict.java

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
package org.testar.monkey.alayer;
3232

3333
import java.io.Serializable;
34+
import java.util.ArrayList;
3435
import java.util.Arrays;
36+
import java.util.List;
3537

3638
import org.testar.monkey.Assert;
3739
import org.testar.monkey.Util;
@@ -93,12 +95,16 @@ public enum Severity {
9395
// WARNING GROUP: ACCESSIBILITY
9496
WARNING_ACCESSIBILITY_FAULT(0.4, "WARNING_ACCESSIBILITY_FAULT"),
9597

96-
/** FAIL (0.5 - 1.0) **/
98+
/** FAIL (0.5 - 0.899) **/
9799

98100
UNREPLAYABLE(0.5, "UNREPLAYABLE"), // Sequence not replayable
99101
SUSPICIOUS_TAG(0.8, "SUSPICIOUS_TAG"), // Suspicious tag
100102
SUSPICIOUS_PROCESS(0.87, "SUSPICIOUS_PROCESS"), // Suspicious message in the process standard output/error
101103
SUSPICIOUS_LOG(0.89, "SUSPICIOUS_LOG"), // Suspicious message in log file or command output (LogOracle)
104+
105+
/** CRITICAL (0.9 - 1.0) **/
106+
107+
CRITICAL(0.9, "CRITICAL"),
102108
NOT_RESPONDING(0.99999990, "NOT_RESPONDING"), // Unresponsive
103109
UNEXPECTEDCLOSE(0.99999999, "UNEXPECTEDCLOSE"), // Crash? Unexpected close?
104110
FAIL(1.0, "FAIL");
@@ -193,29 +199,22 @@ public Visualizer visualizer() {
193199
return visualizer;
194200
}
195201

196-
@Override
197-
public String toString() {
198-
return "severity: " + severity + " info: " + info;
199-
}
200-
201202
/**
202-
* Retrieves the verdict result of joining two verdicts.
203-
* @param verdict A verdict to join with current verdict.
204-
*
205-
* @return A new verdict that is the result of joining the current verdict with the provided verdict.
203+
* Indicates if this verdict is critical (SUT froze or crashed).
204+
*
205+
* @return true if verdict is critical
206206
*/
207-
public Verdict join(Verdict verdict) {
208-
Severity joinedSeverity = Arrays.stream(Severity.values())
209-
.filter(s -> s.getValue() == Math.max(this.severity, verdict.severity()))
210-
.findFirst()
211-
.orElse(Severity.FAIL);
212-
213-
String joinedInfo = this.info.contains(verdict.info()) ? this.info
214-
: (this.severity == Severity.OK.getValue() ? "" : this.info + "\n") + verdict.info();
207+
public boolean isCritical() {
208+
return this.severity() >= Severity.CRITICAL.getValue();
209+
}
215210

216-
Visualizer joinedVisualizer = Visualizer.join(this.visualizer(), verdict.visualizer());
211+
public boolean isCompletion() {
212+
return this.severity() == Severity.LLM_COMPLETE.getValue() || this.severity() == Severity.CONDITION_COMPLETE.getValue();
213+
}
217214

218-
return new Verdict(joinedSeverity, joinedInfo, joinedVisualizer);
215+
@Override
216+
public String toString() {
217+
return "severity: " + severity + " info: " + info;
219218
}
220219

221220
/**
@@ -234,4 +233,15 @@ public boolean equals(Object o) {
234233
&& this.visualizer.equals(other.visualizer);
235234
}
236235

236+
public static boolean helperAreAllVerdictsOK(List<Verdict> verdicts) {
237+
if(verdicts == null || verdicts.isEmpty()) return true;
238+
239+
for (Verdict verdict : verdicts) {
240+
if (verdict.severity() > Severity.OK.getValue()) {
241+
return false;
242+
}
243+
}
244+
return true;
245+
}
246+
237247
}

core/test/org/testar/monkey/alayer/VerdictTest.java

Lines changed: 5 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,16 @@
3535
import java.util.Arrays;
3636

3737
import org.junit.Test;
38-
import org.testar.monkey.alayer.visualizers.RegionsVisualizer;
3938
import org.testar.monkey.alayer.visualizers.ShapeVisualizer;
4039

4140
public class VerdictTest {
4241

43-
private final double DELTA = 0;
44-
45-
private final Visualizer dummyVisualizer = new Visualizer(){
46-
private static final long serialVersionUID = -7830649624698071090L;
47-
public void run(State s, Canvas c, Pen pen) {}
48-
};
49-
5042
private final Visualizer failVisualizer = new ShapeVisualizer(
5143
Pen.PEN_RED,
5244
Rect.from(0, 0, 10, 10),
5345
"Fail Visualizer",
5446
0.5, 0.5);
5547

56-
private final Visualizer issueVisualizer = new RegionsVisualizer(
57-
Pen.PEN_RED,
58-
Arrays.asList(Rect.from(0, 0, 10, 10)),
59-
"Issue Visualizer",
60-
0.5, 0.5);
61-
6248
@Test
6349
public void testToString() {
6450
Verdict v = new Verdict(Verdict.Severity.OK, "This is a test verdict");
@@ -67,54 +53,12 @@ public void testToString() {
6753
}
6854

6955
@Test
70-
public void testJoin() {
71-
Verdict v1 = new Verdict(Verdict.Severity.OK, "Foo Bar");
72-
Verdict v2 = new Verdict(Verdict.Severity.FAIL, "Bar", failVisualizer);
73-
Verdict v3 = new Verdict(Verdict.Severity.OK, "Baz", dummyVisualizer);
74-
Verdict v4 = new Verdict(Verdict.Severity.FAIL, "Exception", issueVisualizer);
75-
Verdict emptyVisualizerVerdict = new Verdict(Verdict.Severity.FAIL, "Empty");
76-
77-
assertTrue("Joining two Verdicts shall create a new Verdict",
78-
v1 != v1.join(v2));
79-
80-
assertEquals("Joining two Verdicts shall set the severity to the maximum of both",
81-
Verdict.Severity.FAIL.getValue(), v3.join(v2).severity(), DELTA);
82-
83-
assertEquals("If a Verdict's info contains the info of the Verdict to be joined with, " +
84-
"then only the containing info shall be used",
85-
"Foo Bar", v1.join(v2).info());
86-
87-
assertEquals("If a Verdict is OK and its info does not contain the info of the Verdict to be joined with, " +
88-
"then the containing info shall be discarded",
89-
"Baz", v1.join(v3).info());
90-
91-
assertEquals("If a Verdict is not OK and its info does not contain the info of the Verdict to be joined with, " +
92-
"then both infos shall be included separated by a line break",
93-
"Bar\nBaz", v2.join(v3).info());
94-
95-
assertTrue("Joining an OK and Fail Verdicts shall use the Visualizer of the Verdict with high severity",
96-
v2.join(v1).visualizer() == failVisualizer);
97-
98-
assertTrue("Joining an OK and Fail Verdicts shall use the Visualizer of the Verdict with high severity",
99-
v1.join(v2).visualizer() == failVisualizer);
100-
101-
assertTrue("Joining Fail and Issue Verdicts must contain Fail Shapes",
102-
v2.join(v4).visualizer().getShapes().containsAll(failVisualizer.getShapes()));
103-
104-
assertTrue("Joining Issue and Fail Verdicts must contain Fail Shapes",
105-
v4.join(v2).visualizer().getShapes().containsAll(failVisualizer.getShapes()));
106-
107-
assertTrue("Joining Fail and Issue Verdicts must contain Issue Shapes",
108-
v2.join(v4).visualizer().getShapes().containsAll(issueVisualizer.getShapes()));
109-
110-
assertTrue("Joining Issue and Fail Verdicts must contain Issue Shapes",
111-
v4.join(v2).visualizer().getShapes().containsAll(issueVisualizer.getShapes()));
112-
113-
assertTrue("Joining Fail and emptyVisualizerVerdict Verdicts must equal Fail visualizer",
114-
v2.join(emptyVisualizerVerdict).visualizer() == failVisualizer);
56+
public void testVerdictHelperAreOK() {
57+
Verdict ok = Verdict.OK;
58+
Verdict warn = new Verdict(Verdict.Severity.SUSPICIOUS_TAG, "Issue", failVisualizer);
11559

116-
assertTrue("Joining emptyVisualizerVerdict and Fail Verdicts must equal Fail visualizer",
117-
emptyVisualizerVerdict.join(v2).visualizer() == failVisualizer);
60+
assertTrue(Verdict.helperAreAllVerdictsOK(Arrays.asList(ok)));
61+
assertFalse(Verdict.helperAreAllVerdictsOK(Arrays.asList(warn)));
11862
}
11963

12064
@Test

statemodel/src/org/testar/statemodel/persistence/orientdb/hydrator/ConcreteStateHydrator.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/***************************************************************************************************
22
*
3-
* Copyright (c) 2018 - 2025 Open Universiteit - www.ou.nl
4-
* Copyright (c) 2018 - 2025 Universitat Politecnica de Valencia - www.upv.es
3+
* Copyright (c) 2018 - 2026 Open Universiteit - www.ou.nl
4+
* Copyright (c) 2018 - 2026 Universitat Politecnica de Valencia - www.upv.es
55
*
66
* Redistribution and use in source and binary forms, with or without
77
* modification, are permitted provided that the following conditions are met:
@@ -39,6 +39,10 @@
3939
import org.testar.statemodel.persistence.orientdb.entity.TypeConvertor;
4040
import org.testar.statemodel.persistence.orientdb.entity.VertexEntity;
4141
import org.testar.statemodel.persistence.orientdb.util.Validation;
42+
43+
import java.util.Collections;
44+
import java.util.List;
45+
4246
import org.testar.monkey.alayer.Tag;
4347
import org.testar.monkey.alayer.TaggableBase;
4448
import org.testar.monkey.alayer.Tags;
@@ -89,18 +93,13 @@ public void hydrate(VertexEntity target, Object source) throws HydrationExceptio
8993
}
9094

9195
// get the oracle verdict and transform it into a custom code
92-
Verdict verdict = attributes.get(Tags.OracleVerdict, null);
96+
List<Verdict> verdicts = attributes.get(Tags.OracleVerdicts, Collections.singletonList(Verdict.OK));
9397
int oracleVerdictCode = 4; // default value
94-
if (verdict != null) {
95-
if (verdict.severity() == Verdict.Severity.OK.getValue()) {
96-
oracleVerdictCode = 1;
97-
}
98-
else if (verdict.severity() == Verdict.Severity.FAIL.getValue()) {
99-
oracleVerdictCode = 2;
100-
}
101-
else if (verdict.severity() > Verdict.Severity.OK.getValue() && verdict.severity() < Verdict.Severity.FAIL.getValue()) {
102-
oracleVerdictCode = 3;
103-
}
98+
if (Verdict.helperAreAllVerdictsOK(verdicts)) {
99+
oracleVerdictCode = 1;
100+
}
101+
else {
102+
oracleVerdictCode = 2;
104103
}
105104
target.addPropertyValue("oracleVerdictCode", new PropertyValue(OType.INTEGER, oracleVerdictCode));
106105
}

testar/resources/settings/01_desktop_calculator/Protocol_01_desktop_calculator.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/***************************************************************************************************
22
*
3-
* Copyright (c) 2020 - 2023 Universitat Politecnica de Valencia - www.upv.es
4-
* Copyright (c) 2020 - 2023 Open Universiteit - www.ou.nl
3+
* Copyright (c) 2020 - 2026 Universitat Politecnica de Valencia - www.upv.es
4+
* Copyright (c) 2020 - 2026 Open Universiteit - www.ou.nl
55
*
66
* Redistribution and use in source and binary forms, with or without
77
* modification, are permitted provided that the following conditions are met:
@@ -41,6 +41,7 @@
4141
import org.testar.protocols.DesktopProtocol;
4242
import org.testar.settings.Settings;
4343

44+
import java.util.List;
4445
import java.util.Set;
4546

4647
/**
@@ -118,18 +119,18 @@ protected State getState(SUT system) throws StateBuildException{
118119
* @return oracle verdict, which determines whether the state is erroneous and why.
119120
*/
120121
@Override
121-
protected Verdict getVerdict(State state){
122+
protected List<Verdict> getVerdicts(State state){
122123
// The super methods implements the implicit online state oracles for:
123124
// system crashes
124125
// non-responsiveness
125126
// suspicious tags
126-
Verdict verdict = super.getVerdict(state);
127+
List<Verdict> verdicts = super.getVerdicts(state);
127128

128129
//--------------------------------------------------------
129130
// MORE SOPHISTICATED STATE ORACLES CAN BE PROGRAMMED HERE
130131
//--------------------------------------------------------
131132

132-
return verdict;
133+
return verdicts;
133134
}
134135

135136
/**

0 commit comments

Comments
 (0)