Skip to content

Commit 8b434e5

Browse files
matchers: code should change (#1548)
1 parent 4bf309e commit 8b434e5

14 files changed

Lines changed: 396 additions & 58 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2023 webtau maintainers
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.testingisdocumenting.webtau.expectation.code
18+
19+
import org.junit.Test
20+
import org.testingisdocumenting.webtau.data.DbEntity
21+
22+
import static org.testingisdocumenting.webtau.Matchers.*
23+
24+
class ChangeCodeMatcherGroovyTest {
25+
@Test
26+
void "change java bean single property"() {
27+
def dbEntity = new DbEntity()
28+
dbEntity.setId("id1")
29+
dbEntity.setDescription("description1")
30+
dbEntity.setValue(100)
31+
32+
code {
33+
// change-single-property
34+
code {
35+
updateDbEntity(dbEntity)
36+
} should change("dbEntity.id", dbEntity::getId)
37+
// change-single-property
38+
} should throwException(AssertionError)
39+
}
40+
41+
@Test
42+
void "change java bean some properties"() {
43+
def dbEntity = new DbEntity()
44+
dbEntity.setId("id1")
45+
dbEntity.setDescription("description1")
46+
dbEntity.setValue(100)
47+
48+
code {
49+
// change-full-property
50+
code {
51+
buggyOperation(dbEntity)
52+
} should change("dbEntity", dbEntity)
53+
// change-full-property
54+
} should throwException(AssertionError)
55+
}
56+
57+
private static void updateDbEntity(DbEntity dbEntity) {
58+
dbEntity.setValue(140)
59+
dbEntity.setDescription("description-changed")
60+
}
61+
62+
private static void buggyOperation(DbEntity dbEntity) {
63+
}
64+
}

webtau-core/src/main/java/org/testingisdocumenting/webtau/Matchers.java

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package org.testingisdocumenting.webtau;
1818

1919
import org.testingisdocumenting.webtau.data.ValuePath;
20+
import org.testingisdocumenting.webtau.data.converters.ObjectProperties;
2021
import org.testingisdocumenting.webtau.data.live.LiveValue;
2122
import org.testingisdocumenting.webtau.expectation.*;
23+
import org.testingisdocumenting.webtau.expectation.code.ChangeCodeMatcher;
2224
import org.testingisdocumenting.webtau.expectation.code.ThrowExceptionMatcher;
2325
import org.testingisdocumenting.webtau.expectation.contain.ContainAllMatcher;
2426
import org.testingisdocumenting.webtau.expectation.contain.ContainMatcher;
@@ -28,6 +30,7 @@
2830

2931
import java.util.Arrays;
3032
import java.util.Collection;
33+
import java.util.concurrent.Callable;
3134
import java.util.function.Supplier;
3235
import java.util.regex.Pattern;
3336

@@ -287,7 +290,7 @@ public static AnyOfMatcher anyOf(Collection<Object> expected) {
287290
* @see #code(CodeBlock)
288291
*
289292
* @param expectedMessage expected exception message
290-
* @return matcher instance
293+
* @return code matcher instance
291294
*/
292295
public static ThrowExceptionMatcher throwException(String expectedMessage) {
293296
return new ThrowExceptionMatcher(expectedMessage);
@@ -303,7 +306,7 @@ public static ThrowExceptionMatcher throwException(String expectedMessage) {
303306
* @see #code(CodeBlock)
304307
*
305308
* @param expectedMessageMatcher expected exception message ValueMatcher
306-
* @return matcher instance
309+
* @return code matcher instance
307310
*/
308311
public static ThrowExceptionMatcher throwException(ValueMatcher expectedMessageMatcher) {
309312
return new ThrowExceptionMatcher(expectedMessageMatcher);
@@ -319,7 +322,7 @@ public static ThrowExceptionMatcher throwException(ValueMatcher expectedMessageM
319322
* @see #code(CodeBlock)
320323
*
321324
* @param expectedMessageRegexp regular pattern to match expected exception message
322-
* @return matcher instance
325+
* @return code matcher instance
323326
*/
324327
public static ThrowExceptionMatcher throwException(Pattern expectedMessageRegexp) {
325328
return new ThrowExceptionMatcher(expectedMessageRegexp);
@@ -335,7 +338,7 @@ public static ThrowExceptionMatcher throwException(Pattern expectedMessageRegexp
335338
* @see #code(CodeBlock)
336339
*
337340
* @param expectedClass expected exception class
338-
* @return matcher instance
341+
* @return code matcher instance
339342
*/
340343
public static ThrowExceptionMatcher throwException(Class<?> expectedClass) {
341344
return new ThrowExceptionMatcher(expectedClass);
@@ -352,7 +355,7 @@ public static ThrowExceptionMatcher throwException(Class<?> expectedClass) {
352355
*
353356
* @param expectedClass expected exception class
354357
* @param expectedMessageRegexp regular pattern to match expected exception message
355-
* @return matcher instance
358+
* @return code matcher instance
356359
*/
357360
public static ThrowExceptionMatcher throwException(Class<?> expectedClass, Pattern expectedMessageRegexp) {
358361
return new ThrowExceptionMatcher(expectedClass, expectedMessageRegexp);
@@ -369,12 +372,13 @@ public static ThrowExceptionMatcher throwException(Class<?> expectedClass, Patte
369372
*
370373
* @param expectedClass expected exception class
371374
* @param expectedMessage expected exception message
372-
* @return matcher instance
375+
* @return code matcher instance
373376
*/
374377
public static ThrowExceptionMatcher throwException(Class<?> expectedClass, String expectedMessage) {
375378
return new ThrowExceptionMatcher(expectedClass, expectedMessage);
376379
}
377380

381+
378382
/**
379383
* Throw exception <code>code</code> matcher.
380384
* <pre>
@@ -391,4 +395,45 @@ public static ThrowExceptionMatcher throwException(Class<?> expectedClass, Strin
391395
public static ThrowExceptionMatcher throwException(Class<?> expectedClass, ValueMatcher expectedMessageMatcher) {
392396
return new ThrowExceptionMatcher(expectedClass, expectedMessageMatcher);
393397
}
398+
399+
/**
400+
* Value change <code>code</code> matcher
401+
* <pre>
402+
* code(() -> {
403+
* updateDbEntity(dbEntity);
404+
* }).should(change("dbEntity.id", dbEntity::getId));
405+
* </pre>
406+
* @param label expression label to use in reporting
407+
* @param valueSupplier value supplier to get before/after values for comparison
408+
* @return code matcher instance
409+
*/
410+
public static ChangeCodeMatcher change(String label, Supplier<Object> valueSupplier) {
411+
return new ChangeCodeMatcher(label, valueSupplier);
412+
}
413+
414+
/**
415+
* Object properties change <code>code</code> matcher
416+
* <pre>
417+
* code(() -> {
418+
* buggyOperation(dbEntity);
419+
* }).should(changeSomeProperties("dbEntity", dbEntity));
420+
* </pre>
421+
* @param label expression label to use in reporting
422+
* @param object object which properties will be extracted for before/after comparison
423+
* @return code matcher instance
424+
*/
425+
public static ChangeCodeMatcher change(String label, Object object) {
426+
// case for Groovy closures to avoid them being treated as Java Beans
427+
if (object instanceof Callable) {
428+
return new ChangeCodeMatcher(label, () -> {
429+
try {
430+
return ((Callable<?>) object).call();
431+
} catch (Exception e) {
432+
throw new RuntimeException(e);
433+
}
434+
});
435+
}
436+
437+
return new ChangeCodeMatcher(label, () -> new ObjectProperties(object));
438+
}
394439
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2023 webtau maintainers
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.testingisdocumenting.webtau.expectation.code;
18+
19+
import org.testingisdocumenting.webtau.data.ValuePath;
20+
import org.testingisdocumenting.webtau.expectation.CodeBlock;
21+
import org.testingisdocumenting.webtau.expectation.CodeMatcher;
22+
import org.testingisdocumenting.webtau.expectation.equality.CompareToComparator;
23+
import org.testingisdocumenting.webtau.reporter.TokenizedMessage;
24+
25+
import java.util.function.Supplier;
26+
27+
import static org.testingisdocumenting.webtau.WebTauCore.*;
28+
29+
public class ChangeCodeMatcher implements CodeMatcher {
30+
private CompareToComparator comparator;
31+
private final Supplier<Object> valueSupplier;
32+
private final String label;
33+
34+
public ChangeCodeMatcher(String label, Supplier<Object> valueSupplier) {
35+
this.label = label;
36+
this.valueSupplier = valueSupplier;
37+
}
38+
39+
@Override
40+
public TokenizedMessage matchingTokenizedMessage() {
41+
comparator = CompareToComparator.comparator();
42+
return tokenizedMessage().matcher("to change value").of().id(label);
43+
}
44+
45+
@Override
46+
public TokenizedMessage matchedTokenizedMessage(CodeBlock codeBlock) {
47+
return tokenizedMessage().matcher("changed value").of().id(label);
48+
}
49+
50+
@Override
51+
public TokenizedMessage mismatchedTokenizedMessage(CodeBlock codeBlock) {
52+
return comparator.generateEqualMatchReport();
53+
}
54+
55+
@Override
56+
public boolean matches(CodeBlock codeBlock) {
57+
comparator.resetReportData();
58+
59+
var before = valueSupplier.get();
60+
codeBlock.execute();
61+
var after = valueSupplier.get();
62+
63+
return comparator.compareIsNotEqual(new ValuePath(label), before, after);
64+
}
65+
}

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/equality/CompareToResult.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public boolean isEqual() {
3232
}
3333

3434
public boolean isNotEqual() {
35-
return equalMessages.isEmpty() || hasExtraOrMissing();
35+
return !notEqualMessages.isEmpty() || hasExtraOrMissing();
3636
}
3737

3838
public boolean isGreater() {

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/equality/handlers/MapAsExpectedCompareToHandlerBase.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.testingisdocumenting.webtau.expectation.equality.handlers;
1919

2020
import org.testingisdocumenting.webtau.data.ValuePath;
21+
import org.testingisdocumenting.webtau.data.converters.ObjectProperties;
2122
import org.testingisdocumenting.webtau.expectation.equality.CompareToComparator;
2223
import org.testingisdocumenting.webtau.expectation.equality.CompareToHandler;
2324

@@ -33,6 +34,10 @@ public boolean handleEquality(Object actual, Object expected) {
3334

3435
@SuppressWarnings("unchecked")
3536
private boolean isMapOfProps(Object o) {
37+
if (o instanceof ObjectProperties) {
38+
return true;
39+
}
40+
3641
if (!(o instanceof Map)) {
3742
return false;
3843
}
@@ -46,7 +51,7 @@ public void compareEqualOnly(CompareToComparator comparator,
4651
ValuePath actualPath,
4752
Object actual,
4853
Object expected) {
49-
Map<String, ?> expectedMap = (Map<String, ?>) expected;
54+
Map<String, ?> expectedMap = extractExpected(expected);
5055
Map<String, ?> actualAsMap = (Map<String, ?>) actual;
5156

5257
expectedMap.keySet().forEach(p -> { // going only through expected keys, ignoring all other bean properties
@@ -61,4 +66,13 @@ public void compareEqualOnly(CompareToComparator comparator,
6166
}
6267
});
6368
}
69+
70+
@SuppressWarnings("unchecked")
71+
private Map<String, ?> extractExpected(Object expected) {
72+
if (expected instanceof Map) {
73+
return (Map<String, ?>) expected;
74+
}
75+
76+
return ((ObjectProperties) expected).getTopLevelProperties();
77+
}
6478
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2023 webtau maintainers
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.testingisdocumenting.webtau.data;
18+
19+
public class DbEntity {
20+
private String id;
21+
private String description;
22+
private Integer value;
23+
24+
public String getId() {
25+
return id;
26+
}
27+
28+
public void setId(String id) {
29+
this.id = id;
30+
}
31+
32+
public String getDescription() {
33+
return description;
34+
}
35+
36+
public void setDescription(String description) {
37+
this.description = description;
38+
}
39+
40+
public Integer getValue() {
41+
return value;
42+
}
43+
44+
public void setValue(Integer value) {
45+
this.value = value;
46+
}
47+
}

webtau-core/src/test/java/org/testingisdocumenting/webtau/data/PeopleDao.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.testingisdocumenting.webtau.data;
1818

1919
import java.util.ArrayList;
20-
import java.util.Arrays;
2120
import java.util.List;
2221
import java.util.stream.Collectors;
2322

@@ -30,7 +29,7 @@ public void add(List<Person> people) {
3029

3130
public List<Person> thisWeekJoiners() {
3231
return people.stream()
33-
.filter(person -> person.getMonthsAtCompany() == 0)
32+
.filter(person -> person.monthsAtCompany() == 0)
3433
.collect(Collectors.toList());
3534
}
3635
}

0 commit comments

Comments
 (0)