Skip to content

Commit d5ec15a

Browse files
feat: Add support of multiple image occurrences (#1445)
1 parent ff10d91 commit d5ec15a

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

src/main/java/io/appium/java_client/imagecomparison/OccurrenceMatchingOptions.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
public class OccurrenceMatchingOptions extends BaseComparisonOptions<OccurrenceMatchingOptions> {
2626
private Double threshold;
27+
private Boolean multiple;
28+
private Integer matchNeighbourThreshold;
2729

2830
/**
2931
* At what normalized threshold to reject an occurrence.
@@ -36,11 +38,38 @@ public OccurrenceMatchingOptions withThreshold(double threshold) {
3638
return this;
3739
}
3840

41+
/**
42+
* Whether to enable the support of multiple image occurrences.
43+
*
44+
* @since Appium 1.21.0
45+
* @return self instance for chaining.
46+
*/
47+
public OccurrenceMatchingOptions enableMultiple() {
48+
this.multiple = true;
49+
return this;
50+
}
51+
52+
/**
53+
* The pixel distance between matches we consider
54+
* to be part of the same template match. This option is only
55+
* considered if multiple matches mode is enabled.
56+
* 10 pixels by default.
57+
*
58+
* @since Appium 1.21.0
59+
* @return self instance for chaining.
60+
*/
61+
public OccurrenceMatchingOptions withMatchNeighbourThreshold(int threshold) {
62+
this.matchNeighbourThreshold = threshold;
63+
return this;
64+
}
65+
3966
@Override
4067
public Map<String, Object> build() {
4168
final ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
4269
builder.putAll(super.build());
4370
ofNullable(threshold).map(x -> builder.put("threshold", x));
71+
ofNullable(matchNeighbourThreshold).map(x -> builder.put("matchNeighbourThreshold", x));
72+
ofNullable(multiple).map(x -> builder.put("multiple", x));
4473
return builder.build();
4574
}
4675
}

src/main/java/io/appium/java_client/imagecomparison/OccurrenceMatchingResult.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,23 @@
1818

1919
import org.openqa.selenium.Rectangle;
2020

21+
import java.util.List;
2122
import java.util.Map;
23+
import java.util.stream.Collectors;
2224

2325
public class OccurrenceMatchingResult extends ComparisonResult {
2426
private static final String RECT = "rect";
27+
private static final String MULTIPLE = "multiple";
28+
29+
private final boolean isAtRoot;
2530

2631
public OccurrenceMatchingResult(Map<String, Object> input) {
32+
this(input, true);
33+
}
34+
35+
private OccurrenceMatchingResult(Map<String, Object> input, boolean isAtRoot) {
2736
super(input);
37+
this.isAtRoot = isAtRoot;
2838
}
2939

3040
/**
@@ -37,4 +47,25 @@ public Rectangle getRect() {
3747
//noinspection unchecked
3848
return mapToRect((Map<String, Object>) getCommandResult().get(RECT));
3949
}
50+
51+
/**
52+
* Returns the list of multiple matches (if any).
53+
* This property only works if the `multiple` option is enabled.
54+
*
55+
* @since Appium 1.21.0
56+
* @return The list containing properties of each single match or an empty list.
57+
* @throws IllegalStateException If the accessor is called on a non-root match instance.
58+
*/
59+
public List<OccurrenceMatchingResult> getMultiple() {
60+
if (!isAtRoot) {
61+
throw new IllegalStateException("Only the root match could contain multiple submatches");
62+
}
63+
verifyPropertyPresence(MULTIPLE);
64+
65+
//noinspection unchecked
66+
List<Map<String, Object>> multiple = (List<Map<String, Object>>) getCommandResult().get(MULTIPLE);
67+
return multiple.stream()
68+
.map((m) -> new OccurrenceMatchingResult(m, false))
69+
.collect(Collectors.toList());
70+
}
4071
}

0 commit comments

Comments
 (0)