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

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

see #20129 - Fix typos and misspellings in the code (patch by gaben)

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