source: josm/trunk/src/org/openstreetmap/josm/data/validation/Test.java@ 13250

Last change on this file since 13250 was 12864, checked in by Don-vip, 7 years ago

fix #15256 - limit roundabout validation test to waynodes all in downloaded area

  • Property svn:eol-style set to native
File size: 11.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.validation;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagConstraints;
7import java.util.ArrayList;
8import java.util.Collection;
9import java.util.List;
10import java.util.Objects;
11import java.util.Optional;
12import java.util.function.Predicate;
13
14import javax.swing.JCheckBox;
15import javax.swing.JPanel;
16
17import org.openstreetmap.josm.command.Command;
18import org.openstreetmap.josm.command.DeleteCommand;
19import org.openstreetmap.josm.data.osm.Node;
20import org.openstreetmap.josm.data.osm.OsmPrimitive;
21import org.openstreetmap.josm.data.osm.Relation;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.data.osm.search.SearchCompiler.InDataSourceArea;
24import org.openstreetmap.josm.data.osm.search.SearchCompiler.NotOutsideDataSourceArea;
25import org.openstreetmap.josm.data.osm.visitor.OsmPrimitiveVisitor;
26import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
27import org.openstreetmap.josm.gui.progress.ProgressMonitor;
28import org.openstreetmap.josm.tools.GBC;
29import org.openstreetmap.josm.tools.Logging;
30import org.openstreetmap.josm.tools.Utils;
31
32/**
33 * Parent class for all validation tests.
34 * <p>
35 * A test is a primitive visitor, so that it can access to all data to be
36 * validated. These primitives are always visited in the same order: nodes
37 * first, then ways.
38 *
39 * @author frsantos
40 */
41public class Test implements OsmPrimitiveVisitor, Comparable<Test> {
42
43 protected static final Predicate<OsmPrimitive> IN_DOWNLOADED_AREA = new NotOutsideDataSourceArea();
44 protected static final Predicate<OsmPrimitive> IN_DOWNLOADED_AREA_STRICT = new InDataSourceArea(true);
45
46 /** Name of the test */
47 protected final String name;
48
49 /** Description of the test */
50 protected final String description;
51
52 /** Whether this test is enabled. Enabled by default */
53 public boolean enabled = true;
54
55 /** The preferences check for validation */
56 protected JCheckBox checkEnabled;
57
58 /** The preferences check for validation on upload */
59 protected JCheckBox checkBeforeUpload;
60
61 /** Whether this test must check before upload. Enabled by default */
62 public boolean testBeforeUpload = true;
63
64 /** Whether this test is performing just before an upload */
65 protected boolean isBeforeUpload;
66
67 /** The list of errors */
68 protected List<TestError> errors = new ArrayList<>(30);
69
70 /** Whether the test is run on a partial selection data */
71 protected boolean partialSelection;
72
73 /** the progress monitor to use */
74 protected ProgressMonitor progressMonitor;
75
76 /** the start time to compute elapsed time when test finishes */
77 protected long startTime;
78
79 /**
80 * Constructor
81 * @param name Name of the test
82 * @param description Description of the test
83 */
84 public Test(String name, String description) {
85 this.name = name;
86 this.description = description;
87 }
88
89 /**
90 * Constructor
91 * @param name Name of the test
92 */
93 public Test(String name) {
94 this(name, null);
95 }
96
97 /**
98 * A test that forwards all primitives to {@link #check(OsmPrimitive)}.
99 */
100 public abstract static class TagTest extends Test {
101 /**
102 * Constructs a new {@code TagTest} with given name and description.
103 * @param name The test name
104 * @param description The test description
105 */
106 public TagTest(String name, String description) {
107 super(name, description);
108 }
109
110 /**
111 * Constructs a new {@code TagTest} with given name.
112 * @param name The test name
113 */
114 public TagTest(String name) {
115 super(name);
116 }
117
118 /**
119 * Checks the tags of the given primitive.
120 * @param p The primitive to test
121 */
122 public abstract void check(OsmPrimitive p);
123
124 @Override
125 public void visit(Node n) {
126 check(n);
127 }
128
129 @Override
130 public void visit(Way w) {
131 check(w);
132 }
133
134 @Override
135 public void visit(Relation r) {
136 check(r);
137 }
138 }
139
140 /**
141 * Initializes any global data used this tester.
142 * @throws Exception When cannot initialize the test
143 */
144 public void initialize() throws Exception {
145 this.startTime = -1;
146 }
147
148 /**
149 * Start the test using a given progress monitor
150 *
151 * @param progressMonitor the progress monitor
152 */
153 public void startTest(ProgressMonitor progressMonitor) {
154 this.progressMonitor = Optional.ofNullable(progressMonitor).orElse(NullProgressMonitor.INSTANCE);
155 String startMessage = tr("Running test {0}", name);
156 this.progressMonitor.beginTask(startMessage);
157 Logging.debug(startMessage);
158 this.errors = new ArrayList<>(30);
159 this.startTime = System.currentTimeMillis();
160 }
161
162 /**
163 * Flag notifying that this test is run over a partial data selection
164 * @param partialSelection Whether the test is on a partial selection data
165 */
166 public void setPartialSelection(boolean partialSelection) {
167 this.partialSelection = partialSelection;
168 }
169
170 /**
171 * Gets the validation errors accumulated until this moment.
172 * @return The list of errors
173 */
174 public List<TestError> getErrors() {
175 return errors;
176 }
177
178 /**
179 * Notification of the end of the test. The tester may perform additional
180 * actions and destroy the used structures.
181 * <p>
182 * If you override this method, don't forget to cleanup {@code progressMonitor}
183 * (most overrides call {@code super.endTest()} to do this).
184 */
185 public void endTest() {
186 progressMonitor.finishTask();
187 progressMonitor = null;
188 if (startTime > 0) {
189 // fix #11567 where elapsedTime is < 0
190 long elapsedTime = Math.max(0, System.currentTimeMillis() - startTime);
191 Logging.debug(tr("Test ''{0}'' completed in {1}", getName(), Utils.getDurationString(elapsedTime)));
192 }
193 }
194
195 /**
196 * Visits all primitives to be tested. These primitives are always visited
197 * in the same order: nodes first, then ways.
198 *
199 * @param selection The primitives to be tested
200 */
201 public void visit(Collection<OsmPrimitive> selection) {
202 if (progressMonitor != null) {
203 progressMonitor.setTicksCount(selection.size());
204 }
205 for (OsmPrimitive p : selection) {
206 if (isCanceled()) {
207 break;
208 }
209 if (isPrimitiveUsable(p)) {
210 p.accept(this);
211 }
212 if (progressMonitor != null) {
213 progressMonitor.worked(1);
214 }
215 }
216 }
217
218 /**
219 * Determines if the primitive is usable for tests.
220 * @param p The primitive
221 * @return {@code true} if the primitive can be tested, {@code false} otherwise
222 */
223 public boolean isPrimitiveUsable(OsmPrimitive p) {
224 return p.isUsable() && (!(p instanceof Way) || (((Way) p).getNodesCount() > 1)); // test only Ways with at least 2 nodes
225 }
226
227 @Override
228 public void visit(Node n) {
229 // To be overridden in subclasses
230 }
231
232 @Override
233 public void visit(Way w) {
234 // To be overridden in subclasses
235 }
236
237 @Override
238 public void visit(Relation r) {
239 // To be overridden in subclasses
240 }
241
242 /**
243 * Allow the tester to manage its own preferences
244 * @param testPanel The panel to add any preferences component
245 */
246 public void addGui(JPanel testPanel) {
247 checkEnabled = new JCheckBox(name, enabled);
248 checkEnabled.setToolTipText(description);
249 testPanel.add(checkEnabled, GBC.std());
250
251 GBC a = GBC.eol();
252 a.anchor = GridBagConstraints.EAST;
253 checkBeforeUpload = new JCheckBox();
254 checkBeforeUpload.setSelected(testBeforeUpload);
255 testPanel.add(checkBeforeUpload, a);
256 }
257
258 /**
259 * Called when the used submits the preferences
260 * @return {@code true} if restart is required, {@code false} otherwise
261 */
262 public boolean ok() {
263 enabled = checkEnabled.isSelected();
264 testBeforeUpload = checkBeforeUpload.isSelected();
265 return false;
266 }
267
268 /**
269 * Fixes the error with the appropriate command
270 *
271 * @param testError error to fix
272 * @return The command to fix the error
273 */
274 public Command fixError(TestError testError) {
275 return null;
276 }
277
278 /**
279 * Returns true if the given error can be fixed automatically
280 *
281 * @param testError The error to check if can be fixed
282 * @return true if the error can be fixed
283 */
284 public boolean isFixable(TestError testError) {
285 return false;
286 }
287
288 /**
289 * Returns true if this plugin must check the uploaded data before uploading
290 * @return true if this plugin must check the uploaded data before uploading
291 */
292 public boolean testBeforeUpload() {
293 return testBeforeUpload;
294 }
295
296 /**
297 * Sets the flag that marks an upload check
298 * @param isUpload if true, the test is before upload
299 */
300 public void setBeforeUpload(boolean isUpload) {
301 this.isBeforeUpload = isUpload;
302 }
303
304 /**
305 * Returns the test name.
306 * @return The test name
307 */
308 public String getName() {
309 return name;
310 }
311
312 /**
313 * Determines if the test has been canceled.
314 * @return {@code true} if the test has been canceled, {@code false} otherwise
315 */
316 public boolean isCanceled() {
317 return progressMonitor != null ? progressMonitor.isCanceled() : false;
318 }
319
320 /**
321 * Build a Delete command on all primitives that have not yet been deleted manually by user, or by another error fix.
322 * If all primitives have already been deleted, null is returned.
323 * @param primitives The primitives wanted for deletion
324 * @return a Delete command on all primitives that have not yet been deleted, or null otherwise
325 */
326 protected final Command deletePrimitivesIfNeeded(Collection<? extends OsmPrimitive> primitives) {
327 Collection<OsmPrimitive> primitivesToDelete = new ArrayList<>();
328 for (OsmPrimitive p : primitives) {
329 if (!p.isDeleted()) {
330 primitivesToDelete.add(p);
331 }
332 }
333 if (!primitivesToDelete.isEmpty()) {
334 return DeleteCommand.delete(primitivesToDelete);
335 } else {
336 return null;
337 }
338 }
339
340 /**
341 * Determines if the specified primitive denotes a building.
342 * @param p The primitive to be tested
343 * @return True if building key is set and different from no,entrance
344 */
345 protected static final boolean isBuilding(OsmPrimitive p) {
346 return p.hasTagDifferent("building", "no", "entrance");
347 }
348
349 @Override
350 public int hashCode() {
351 return Objects.hash(name, description);
352 }
353
354 @Override
355 public boolean equals(Object obj) {
356 if (this == obj) return true;
357 if (obj == null || getClass() != obj.getClass()) return false;
358 Test test = (Test) obj;
359 return Objects.equals(name, test.name) &&
360 Objects.equals(description, test.description);
361 }
362
363 @Override
364 public int compareTo(Test t) {
365 return name.compareTo(t.name);
366 }
367}
Note: See TracBrowser for help on using the repository browser.