Skip to content

Commit 4bc22a5

Browse files
matchers: code should[Not] change (#1557)
1 parent 30b98f0 commit 4bc22a5

File tree

11 files changed

+230
-18
lines changed

11 files changed

+230
-18
lines changed

webtau-core-groovy/src/test/groovy/org/testingisdocumenting/webtau/expectation/code/ChangeCodeMatcherGroovyTest.groovy

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,32 @@ class ChangeCodeMatcherGroovyTest {
5454
} should throwException(AssertionError)
5555
}
5656

57+
@Test
58+
void "fail not to change java bean properties"() {
59+
def dbEntity = new DbEntity()
60+
dbEntity.setId("id1")
61+
dbEntity.setDescription("description1")
62+
dbEntity.setValue(100)
63+
64+
code {
65+
// change-not-full-property
66+
code {
67+
calculatePrice(dbEntity)
68+
} shouldNot change("dbEntity", dbEntity)
69+
// change-not-full-property
70+
} should throwException(AssertionError)
71+
}
72+
5773
private static void updateDbEntity(DbEntity dbEntity) {
5874
dbEntity.setValue(140)
5975
dbEntity.setDescription("description-changed")
6076
}
6177

78+
private void calculatePrice(DbEntity dbEntity) {
79+
dbEntity.setValue(110)
80+
dbEntity.setDescription("description-changed")
81+
}
82+
6283
private static void buggyOperation(DbEntity dbEntity) {
6384
}
6485
}

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/ActualCode.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,19 @@ public ActualCode(CodeBlock actual) {
3535
@Override
3636
public void should(CodeMatcher codeMatcher) {
3737
executeStep(codeMatcher,
38+
false,
3839
tokenizedMessage().action("expecting"),
3940
() -> shouldStep(codeMatcher), StepReportOptions.REPORT_ALL);
4041
}
4142

43+
@Override
44+
public void shouldNot(CodeMatcher codeMatcher) {
45+
executeStep(codeMatcher,
46+
true,
47+
tokenizedMessage().action("expecting"),
48+
() -> shouldNotStep(codeMatcher), StepReportOptions.REPORT_ALL);
49+
}
50+
4251
private void shouldStep(CodeMatcher codeMatcher) {
4352
boolean matches = codeMatcher.matches(actual);
4453

@@ -49,6 +58,16 @@ private void shouldStep(CodeMatcher codeMatcher) {
4958
}
5059
}
5160

61+
private void shouldNotStep(CodeMatcher codeMatcher) {
62+
boolean matches = codeMatcher.negativeMatches(actual);
63+
64+
if (matches) {
65+
handleMatch(codeMatcher);
66+
} else {
67+
handleMismatch(codeMatcher, codeMatcher.negativeMismatchedTokenizedMessage(actual));
68+
}
69+
}
70+
5271
private void handleMatch(CodeMatcher codeMatcher) {
5372
ExpectationHandlers.onCodeMatch(codeMatcher);
5473
}
@@ -62,14 +81,16 @@ private void handleMismatch(CodeMatcher codeMatcher, TokenizedMessage message) {
6281
}
6382

6483
private void executeStep(CodeMatcher codeMatcher,
84+
boolean isNegative,
6585
TokenizedMessage messageStart,
6686
Runnable expectationValidation,
6787
StepReportOptions stepReportOptions) {
6888
TokenizedMessage codeDescription = tokenizedMessage().id("code");
6989
WebTauStep step = createStep(
70-
messageStart.add(codeDescription).add(codeMatcher.matchingTokenizedMessage()),
90+
messageStart.add(codeDescription).add(isNegative ?
91+
codeMatcher.negativeMatchingTokenizedMessage() : codeMatcher.matchingTokenizedMessage()),
7192
() -> tokenizedMessage(codeDescription)
72-
.add(codeMatcher.matchedTokenizedMessage(actual)),
93+
.add(isNegative ? codeMatcher.negativeMatchedTokenizedMessage(actual) : codeMatcher.matchedTokenizedMessage(actual)),
7394
expectationValidation);
7495
step.setClassifier(WebTauStepClassifiers.MATCHER);
7596

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/ActualCodeExpectations.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@
1818

1919
public interface ActualCodeExpectations {
2020
void should(CodeMatcher codeMatcher);
21+
void shouldNot(CodeMatcher codeMatcher);
2122
}

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/CodeMatcher.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.testingisdocumenting.webtau.expectation;
1818

19+
import org.testingisdocumenting.webtau.data.ValuePath;
1920
import org.testingisdocumenting.webtau.reporter.TokenizedMessage;
2021

2122
public interface CodeMatcher {
@@ -37,4 +38,31 @@ public interface CodeMatcher {
3738
TokenizedMessage mismatchedTokenizedMessage(CodeBlock codeBlock);
3839

3940
boolean matches(CodeBlock codeBlock);
41+
42+
/**
43+
* @return about to start negative matching (shouldNot/waitToNot case) message
44+
*/
45+
TokenizedMessage negativeMatchingTokenizedMessage();
46+
47+
/**
48+
* @param codeBlock matching code block
49+
* @return negative match message (shouldNot/waitToNot case)
50+
* @see ValuePath
51+
*/
52+
TokenizedMessage negativeMatchedTokenizedMessage(CodeBlock codeBlock);
53+
54+
/**
55+
* @param codeBlock matching code block
56+
* @return negative mismatch message (shouldNot/waitToNot case)
57+
* @see ValuePath
58+
*/
59+
TokenizedMessage negativeMismatchedTokenizedMessage(CodeBlock codeBlock);
60+
61+
/**
62+
* Evaluates matcher. Called only for shouldNot/waitToNot
63+
* @param codeBlock matching code block
64+
* @return true in case of a negative match
65+
* @see ValuePath
66+
*/
67+
boolean negativeMatches(CodeBlock codeBlock);
4068
}

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/ValueMatcher.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ default ValueConverter valueConverter() {
3535
return ValueConverter.EMPTY;
3636
}
3737

38-
// should
38+
// positive matching
3939

4040
/**
4141
* @return about to start matching message
@@ -76,33 +76,33 @@ default Set<ValuePath> mismatchedPaths() {
7676
}
7777

7878
/**
79-
* Evaluates matcher. Called only for should
79+
* Evaluates matcher. Called for should/wait
8080
* @param actualPath path to the value
8181
* @param actual actual value
8282
* @return true in case of a match
8383
* @see ValuePath
8484
*/
8585
boolean matches(ValuePath actualPath, Object actual);
8686

87-
// shouldNot
87+
// negative matching
8888

8989
/**
90-
* @return about to start negative matching (shouldNot case) message
90+
* @return about to start negative matching (shouldNot/waitToNot case) message
9191
*/
9292
TokenizedMessage negativeMatchingTokenizedMessage(ValuePath actualPath, Object actual);
9393

9494
/**
9595
* @param actualPath path to the value
9696
* @param actual actual value
97-
* @return negative match message (shouldNot case)
97+
* @return negative match message (shouldNot/waitToNot case)
9898
* @see ValuePath
9999
*/
100100
TokenizedMessage negativeMatchedTokenizedMessage(ValuePath actualPath, Object actual);
101101

102102
/**
103103
* @param actualPath path to the value
104104
* @param actual actual value
105-
* @return negative mismatch message (shouldNot case)
105+
* @return negative mismatch message (shouldNot/waitToNot case)
106106
* @see ValuePath
107107
*/
108108
TokenizedMessage negativeMismatchedTokenizedMessage(ValuePath actualPath, Object actual);
@@ -111,7 +111,7 @@ default Set<ValuePath> mismatchedPaths() {
111111
* Evaluates matcher. Called only for shouldNot
112112
* @param actualPath path to the value
113113
* @param actual actual value
114-
* @return true in case of a negative match (shouldNot case)
114+
* @return true in case of a negative match (shouldNot/waitToNot case)
115115
* @see ValuePath
116116
*/
117117
boolean negativeMatches(ValuePath actualPath, Object actual);

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/code/ChangeCodeMatcher.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,33 @@ public boolean matches(CodeBlock codeBlock) {
6060
codeBlock.execute();
6161
var after = valueSupplier.get();
6262

63-
return comparator.compareIsNotEqual(new ValuePath(label), before, after);
63+
return comparator.compareIsNotEqual(new ValuePath(label), after, before);
64+
}
65+
66+
@Override
67+
public TokenizedMessage negativeMatchingTokenizedMessage() {
68+
comparator = CompareToComparator.comparator(CompareToComparator.AssertionMode.NOT_EQUAL);
69+
return tokenizedMessage().matcher("to not change value").of().id(label);
70+
}
71+
72+
@Override
73+
public TokenizedMessage negativeMatchedTokenizedMessage(CodeBlock codeBlock) {
74+
return tokenizedMessage().matcher("didn't change value").of().id(label);
75+
}
76+
77+
@Override
78+
public TokenizedMessage negativeMismatchedTokenizedMessage(CodeBlock codeBlock) {
79+
return comparator.generateNotEqualMatchReport();
80+
}
81+
82+
@Override
83+
public boolean negativeMatches(CodeBlock codeBlock) {
84+
comparator.resetReportData();
85+
86+
var before = valueSupplier.get();
87+
codeBlock.execute();
88+
var after = valueSupplier.get();
89+
90+
return comparator.compareIsEqual(new ValuePath(label), after, before);
6491
}
6592
}

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/code/ThrowExceptionMatcher.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,26 @@ public boolean matches(CodeBlock codeBlock) {
127127
return comparator.compareIsEqual(createActualPath("exception"), actualThrownAsMap, expectedAsMap);
128128
}
129129

130+
@Override
131+
public TokenizedMessage negativeMatchingTokenizedMessage() {
132+
throw new UnsupportedOperationException();
133+
}
134+
135+
@Override
136+
public TokenizedMessage negativeMatchedTokenizedMessage(CodeBlock codeBlock) {
137+
throw new UnsupportedOperationException();
138+
}
139+
140+
@Override
141+
public TokenizedMessage negativeMismatchedTokenizedMessage(CodeBlock codeBlock) {
142+
throw new UnsupportedOperationException();
143+
}
144+
145+
@Override
146+
public boolean negativeMatches(CodeBlock codeBlock) {
147+
throw new UnsupportedOperationException();
148+
}
149+
130150
private Map<String, Object> buildThrownToUseForCompare() {
131151
return createMap(thrownMessage, thrownClass);
132152
}

webtau-core/src/test/java/org/testingisdocumenting/webtau/expectation/code/ChangeCodeMatcherJavaTest.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ public void changeJavaBeanSingleProperty() {
3535
}).should(change("dbEntity.value", dbEntity::getValue));
3636
}
3737

38+
@Test
39+
public void shouldNotChangeJavaBeanSingleProperty() {
40+
var dbEntity = new DbEntity();
41+
dbEntity.setId("id1");
42+
dbEntity.setDescription("description1");
43+
dbEntity.setValue(100);
44+
45+
code(() -> {
46+
changeFreeOperation(dbEntity);
47+
}).shouldNot(change("dbEntity.value", dbEntity::getValue));
48+
}
49+
3850
@Test
3951
public void failToChangeJavaBeanSingleProperty() {
4052
var dbEntity = new DbEntity();
@@ -55,6 +67,26 @@ public void failToChangeJavaBeanSingleProperty() {
5567
});
5668
}
5769

70+
@Test
71+
public void failToNotChangeJavaBeanSingleProperty() {
72+
var dbEntity = new DbEntity();
73+
dbEntity.setId("id1");
74+
dbEntity.setDescription("description1");
75+
dbEntity.setValue(100);
76+
77+
runExpectExceptionCaptureAndValidateOutput(AssertionError.class, "javabean-value-not-change-fail-output", """
78+
> expecting code to not change value of dbEntity.value
79+
X failed expecting code to not change value of dbEntity.value:
80+
actual: 140 <java.lang.Integer>
81+
expected: 100 <java.lang.Integer> (Xms)""", () -> {
82+
// change-not-single-property
83+
code(() -> {
84+
changeFreeBuggyOperation(dbEntity);
85+
}).shouldNot(change("dbEntity.value", dbEntity::getValue));
86+
// change-not-single-property
87+
});
88+
}
89+
5890
@Test
5991
public void changeJavaBeanProperties() {
6092
var dbEntity = new DbEntity();
@@ -91,11 +123,47 @@ public void failToChangeJavaBeanProperties() {
91123
});
92124
}
93125

126+
@Test
127+
public void failNotToChangeJavaBeanProperties() {
128+
var dbEntity = new DbEntity();
129+
dbEntity.setId("id1");
130+
dbEntity.setDescription("description1");
131+
dbEntity.setValue(100);
132+
133+
runExpectExceptionCaptureAndValidateOutput(AssertionError.class, "javabean-fail-not-to-change-output", """
134+
> expecting code to not change value of dbEntity
135+
X failed expecting code to not change value of dbEntity:
136+
dbEntity.description: actual: "description-changed" <java.lang.String>
137+
expected: "description1" <java.lang.String>
138+
^
139+
dbEntity.value: actual: 110 <java.lang.Integer>
140+
expected: 100 <java.lang.Integer> (Xms)""", () -> {
141+
// change-not-full-property
142+
code(() -> {
143+
calculatePrice(dbEntity);
144+
}).shouldNot(change("dbEntity", dbEntity));
145+
// change-not-full-property
146+
});
147+
}
148+
94149
private void updateDbEntity(DbEntity dbEntity) {
95150
dbEntity.setValue(140);
96151
dbEntity.setDescription("description-changed");
97152
}
98153

154+
private void calculatePrice(DbEntity dbEntity) {
155+
dbEntity.setValue(110);
156+
dbEntity.setDescription("description-changed");
157+
}
158+
99159
private void buggyOperation(DbEntity dbEntity) {
100160
}
161+
162+
private void changeFreeOperation(DbEntity dbEntity) {
163+
}
164+
165+
private void changeFreeBuggyOperation(DbEntity dbEntity) {
166+
dbEntity.setValue(140);
167+
dbEntity.setDescription("description-changed");
168+
}
101169
}

0 commit comments

Comments
 (0)