source: josm/trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerAsserts.java@ 18365

Last change on this file since 18365 was 18365, checked in by Don-vip, 2 years ago

see #15182 - make JOSM callable as standalone validator (patch by taylor.smock)

File size: 6.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.validation.tests;
3
4import java.text.MessageFormat;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.Collections;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Map;
11import java.util.Optional;
12import java.util.Set;
13import java.util.function.Consumer;
14import java.util.stream.Collectors;
15
16import org.openstreetmap.josm.command.Command;
17import org.openstreetmap.josm.data.coor.LatLon;
18import org.openstreetmap.josm.data.osm.DataSet;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.OsmUtils;
21import org.openstreetmap.josm.data.validation.TestError;
22import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory;
23import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory;
24import org.openstreetmap.josm.gui.mappaint.mapcss.LiteralExpression;
25import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
26import org.openstreetmap.josm.tools.DefaultGeoProperty;
27import org.openstreetmap.josm.tools.GeoProperty;
28import org.openstreetmap.josm.tools.GeoPropertyIndex;
29import org.openstreetmap.josm.tools.Logging;
30import org.openstreetmap.josm.tools.Territories;
31
32/**
33 * Utility class for checking rule assertions of {@link MapCSSTagCheckerRule}.
34 */
35final class MapCSSTagCheckerAsserts {
36
37 private MapCSSTagCheckerAsserts() {
38 // private constructor
39 }
40
41 private static final ArrayList<MapCSSTagCheckerRule> previousChecks = new ArrayList<>();
42
43 /**
44 * Checks that rule assertions are met for the given set of TagChecks.
45 * @param check The TagCheck for which assertions have to be checked
46 * @param assertions The assertions to check (map values correspond to expected result)
47 * @param assertionConsumer The handler for assertion error messages
48 */
49 static void checkAsserts(final MapCSSTagCheckerRule check, final Map<String, Boolean> assertions,
50 final Consumer<String> assertionConsumer) {
51 final DataSet ds = new DataSet();
52 Logging.debug("Check: {0}", check);
53 for (final Map.Entry<String, Boolean> i : assertions.entrySet()) {
54 Logging.debug("- Assertion: {0}", i);
55 final OsmPrimitive p = OsmUtils.createPrimitive(i.getKey(), getLocation(check), true);
56 // Build minimal ordered list of checks to run to test the assertion
57 List<Set<MapCSSTagCheckerRule>> checksToRun = new ArrayList<>();
58 Set<MapCSSTagCheckerRule> checkDependencies = getTagCheckDependencies(check, previousChecks);
59 if (!checkDependencies.isEmpty()) {
60 checksToRun.add(checkDependencies);
61 }
62 checksToRun.add(Collections.singleton(check));
63 // Add primitive to dataset to avoid DataIntegrityProblemException when evaluating selectors
64 ds.addPrimitiveRecursive(p);
65 final Collection<TestError> pErrors = MapCSSTagChecker.getErrorsForPrimitive(p, true, checksToRun);
66 Logging.debug("- Errors: {0}", pErrors);
67 final boolean isError = pErrors.stream().anyMatch(e -> e.getTester() instanceof MapCSSTagChecker.MapCSSTagCheckerAndRule
68 && ((MapCSSTagChecker.MapCSSTagCheckerAndRule) e.getTester()).rule.equals(check.rule));
69 if (isError != i.getValue()) {
70 assertionConsumer.accept(MessageFormat.format("Expecting test ''{0}'' (i.e., {1}) to {2} {3} (i.e., {4})",
71 check.getMessage(p), check.rule.selectors, i.getValue() ? "match" : "not match", i.getKey(), p.getKeys()));
72 }
73 if (isError) {
74 // Check that autofix works as expected
75 Command fix = check.fixPrimitive(p);
76 if (fix != null && fix.executeCommand() && !MapCSSTagChecker.getErrorsForPrimitive(p, true, checksToRun).isEmpty()) {
77 assertionConsumer.accept(MessageFormat.format("Autofix does not work for test ''{0}'' (i.e., {1})",
78 check.getMessage(p), check.rule.selectors));
79 }
80 }
81 ds.removePrimitive(p);
82 }
83 previousChecks.add(check);
84 }
85
86 public static void clear() {
87 previousChecks.clear();
88 previousChecks.trimToSize();
89 }
90
91 private static LatLon getLocation(MapCSSTagCheckerRule check) {
92 Optional<String> inside = getFirstInsideCountry(check);
93 if (inside.isPresent()) {
94 GeoPropertyIndex<Boolean> index = Territories.getGeoPropertyIndex(inside.get());
95 if (index != null) {
96 GeoProperty<Boolean> prop = index.getGeoProperty();
97 if (prop instanceof DefaultGeoProperty) {
98 return ((DefaultGeoProperty) prop).getRandomLatLon();
99 }
100 }
101 }
102 return LatLon.ZERO;
103 }
104
105 private static Optional<String> getFirstInsideCountry(MapCSSTagCheckerRule check) {
106 return check.rule.selectors.stream()
107 .filter(s -> s instanceof Selector.GeneralSelector)
108 .flatMap(s -> ((Selector.GeneralSelector) s).getConditions().stream())
109 .filter(c -> c instanceof ConditionFactory.ExpressionCondition)
110 .map(c -> ((ConditionFactory.ExpressionCondition) c).getExpression())
111 .filter(c -> c instanceof ExpressionFactory.IsInsideFunction)
112 .map(c -> (ExpressionFactory.IsInsideFunction) c)
113 .map(ExpressionFactory.IsInsideFunction::getArg)
114 .filter(e -> e instanceof LiteralExpression)
115 .map(e -> ((LiteralExpression) e).getLiteral())
116 .filter(l -> l instanceof String)
117 .map(l -> ((String) l).split(",", -1)[0])
118 .findFirst();
119 }
120
121 /**
122 * Returns the set of tagchecks on which this check depends on.
123 * @param check the tagcheck
124 * @param schecks the collection of tagchecks to search in
125 * @return the set of tagchecks on which this check depends on
126 * @since 7881
127 */
128 private static Set<MapCSSTagCheckerRule> getTagCheckDependencies(MapCSSTagCheckerRule check,
129 Collection<MapCSSTagCheckerRule> schecks) {
130 Set<MapCSSTagCheckerRule> result = new HashSet<>();
131 Set<String> classes = check.rule.selectors.stream()
132 .filter(s -> s instanceof Selector.AbstractSelector)
133 .flatMap(s -> ((Selector.AbstractSelector) s).getConditions().stream())
134 .filter(c -> c instanceof ConditionFactory.ClassCondition)
135 .map(c -> ((ConditionFactory.ClassCondition) c).id)
136 .collect(Collectors.toSet());
137 if (schecks != null && !classes.isEmpty()) {
138 return schecks.stream()
139 .filter(tc -> !check.equals(tc))
140 .filter(tc -> tc.setClassExpressions.stream().anyMatch(classes::contains))
141 .collect(Collectors.toSet());
142 }
143 return result;
144 }
145}
Note: See TracBrowser for help on using the repository browser.