Changeset 19619 in josm
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/tests/PowerLines.java
r18871 r19619 12 12 import java.util.HashMap; 13 13 import java.util.HashSet; 14 import java.util.LinkedHashSet; 14 15 import java.util.List; 15 16 import java.util.Map; 17 import java.util.Map.Entry; 16 18 import java.util.Set; 19 import java.util.stream.Collectors; 17 20 18 21 import org.openstreetmap.josm.data.coor.ILatLon; … … 76 79 private double hillyCompensation; 77 80 private double hillyThreshold; 78 private final Set<Node> badConnections = new HashSet<>();79 private final Set<Node> missingTags = new HashSet<>();81 private final Map<Node, Set<OsmPrimitive>> badConnections = new HashMap<>(); 82 private final Map<Node, Set<OsmPrimitive>> missingTags = new HashMap<>(); 80 83 private final Set<Way> wrongLineType = new HashSet<>(); 81 84 private final Set<WaySegment> missingNodes = new HashSet<>(); … … 99 102 @Override 100 103 public void visit(Node n) { 101 boolean nodeInLineOrCable = false; 102 boolean connectedToUnrelated = false; 103 for (Way parent : n.getParentWays()) { 104 if (parent.hasTag(POWER, "line", MINOR_LINE, "cable")) 105 nodeInLineOrCable = true; 106 else if (!isRelatedToPower(parent)) 107 connectedToUnrelated = true; 108 } 109 if (nodeInLineOrCable && connectedToUnrelated) 110 badConnections.add(n); 104 if (!n.isConnectionNode() || n.referrers(Way.class).noneMatch(w -> isPowerLineOrCable(w))) 105 return; 106 107 List<Way> unrelatedParents = n.referrers(Way.class).filter(w -> !isPowerLineOrCable(w) && !isRelatedToPower(w)) 108 .collect(Collectors.toList()); 109 if (!unrelatedParents.isEmpty()) { 110 Set<OsmPrimitive> set = badConnections.computeIfAbsent(n, k -> new HashSet<>()); 111 set.addAll(unrelatedParents); 112 } 111 113 } 112 114 … … 163 165 } 164 166 // Then return the errors 165 for (Node n : missingTags) { 167 for (Entry<Node, Set<OsmPrimitive>> entry : missingTags.entrySet()) { 168 Node n = entry.getKey(); 166 169 if (!isInPowerStation(n)) { 167 170 errors.add(TestError.builder(this, Severity.WARNING, POWER_SUPPORT) 168 171 // the "missing tag" grouping can become broken if the MapCSS message get reworded 169 172 .message(tr("missing tag"), tr("node without power=*")) 170 .primitives(n) 173 .primitives(getAllPrimitives(entry)) 174 .highlight(n) 171 175 .build()); 172 176 } 173 177 } 174 178 175 for ( Node n: badConnections) {179 for (Entry<Node, Set<OsmPrimitive>> entry : badConnections.entrySet()) { 176 180 errors.add(TestError.builder(this, Severity.WARNING, POWER_CONNECTION) 177 181 .message(tr("Node connects a power line or cable with an object " 178 182 + "which is not related to the power infrastructure")) 179 .primitives(n) 183 .primitives(getAllPrimitives(entry)) 184 .highlight(entry.getKey()) 180 185 .build()); 181 186 } … … 222 227 223 228 super.endTest(); 229 } 230 231 /** 232 * Combine the node and the related objects. 233 * @param entry a map entry with a node and related objects 234 * @return set containing the node and the related objects 235 */ 236 private Collection<? extends OsmPrimitive> getAllPrimitives(Entry<Node, Set<OsmPrimitive>> entry) { 237 Set<OsmPrimitive> primitives = new LinkedHashSet<>(); 238 primitives.add(entry.getKey()); 239 primitives.addAll(entry.getValue()); 240 return primitives; 224 241 } 225 242 … … 254 271 /// handle missing power line support tags (e.g. tower) 255 272 if (!isPowerTower(n) && !isPowerInfrastructure(n) && IN_DOWNLOADED_AREA.test(n) 256 && (!w.isFirstLastNode(n) || !isPowerStation(n))) 257 missingTags.add(n); 273 && (!w.isFirstLastNode(n) || !isPowerStation(n))) { 274 Set<OsmPrimitive> set = missingTags.computeIfAbsent(n, k -> new HashSet<>()); 275 set.add(w); 276 } 258 277 259 278 /// handle missing nodes … … 670 689 671 690 /** 691 * Determines if the specified way denotes a power line or cable. 692 * @param w The way to be tested 693 * @return {@code true} if power key is set and equal to line,minor_line or cable 694 */ 695 protected static boolean isPowerLineOrCable(Way w) { 696 return isPowerIn(w, Arrays.asList("line", MINOR_LINE, "cable")); 697 } 698 699 /** 672 700 * Determines if the specified primitive denotes a power station. 673 701 * @param p The primitive to be tested -
trunk/test/unit/org/openstreetmap/josm/data/validation/tests/PowerLinesTest.java
r19519 r19619 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.validation.tests; 3 4 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;5 import static org.junit.jupiter.api.Assertions.assertFalse;6 import static org.junit.jupiter.api.Assertions.assertTrue;7 8 import java.util.ArrayList;9 3 10 4 import org.junit.jupiter.api.BeforeEach; … … 18 12 import org.openstreetmap.josm.data.osm.TagMap; 19 13 import org.openstreetmap.josm.data.osm.Way; 14 import org.openstreetmap.josm.data.validation.TestError; 20 15 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 21 16 import org.openstreetmap.josm.testutils.annotations.BasicPreferences; 22 17 import org.openstreetmap.josm.testutils.annotations.Projection; 18 19 import java.util.ArrayList; 20 21 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 22 import static org.junit.jupiter.api.Assertions.assertFalse; 23 import static org.junit.jupiter.api.Assertions.assertTrue; 23 24 24 25 /** … … 160 161 assertTrue(this.powerLines.getErrors().isEmpty()); 161 162 } 163 164 /** 165 * Test for ticket #24851. 166 * Simulates connecting a power line to an existing highway node without power tags. 167 * Validates that the resulting error contains both the Node AND the Way, so it 168 * doesn't get filtered out during partial validation on upload. 169 */ 170 @Test 171 void testTicket24851_ReportExistingNonPowerNodes() { 172 Node sharedNode = new Node(new LatLon(0, 0)); // no power tag attached 173 174 // unrelated highway way 175 Way highway = TestUtils.newWay("highway=unclassified", 176 sharedNode, new Node(new LatLon(0.1, 0))); 177 178 // power line way 179 Way powerline = TestUtils.newWay("power=line", 180 sharedNode, new Node(new LatLon(0, 0.1))); 181 182 // second node has a valid tag 183 powerline.getNode(1).put("power", "tower"); 184 185 ds.addPrimitiveRecursive(highway); 186 ds.addPrimitiveRecursive(powerline); 187 188 powerLines.startTest(NullProgressMonitor.INSTANCE); 189 for (Way w : ds.getWays()) { 190 powerLines.visit(w); 191 } 192 for (Node n : ds.getNodes()) { 193 powerLines.visit(n); 194 } 195 powerLines.endTest(); 196 197 assertFalse(powerLines.getErrors().isEmpty(), "Errors should be generated for the missing tag and bad connection"); 198 199 boolean foundSupportError = false; 200 boolean foundConnectionError = false; 201 202 for (TestError error : powerLines.getErrors()) { 203 // verify POWER_SUPPORT behavior (missing tag) 204 if (error.getCode() == PowerLines.POWER_SUPPORT && error.getPrimitives().contains(sharedNode)) { 205 foundSupportError = true; 206 assertTrue(error.getPrimitives().contains(powerline), 207 "MUST contain the parent powerline way. This prevents JOSM from discarding the error " + 208 "during partial validation if the node itself was unmodified."); 209 } 210 // verify POWER_CONNECTION behavior (bad connection) 211 if (error.getCode() == PowerLines.POWER_CONNECTION && error.getPrimitives().contains(sharedNode)) { 212 foundConnectionError = true; 213 assertTrue(error.getPrimitives().contains(highway), 214 "MUST contain the unrelated parent way. This prevents JOSM from discarding the error" + 215 "during partial validation if the node itself was unmodified."); 216 } 217 } 218 219 assertTrue(foundSupportError, "Should report missing power tag on shared node"); 220 assertTrue(foundConnectionError, "Should report bad connection on shared node"); 221 } 162 222 }
Note:
See TracChangeset
for help on using the changeset viewer.
