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

Last change on this file since 9864 was 9397, checked in by simon04, 8 years ago

see #12325 - Do not exclude the test for non-downloaded datasets, fix unit test

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