Ticket #20182: 20182.patch
File 20182.patch, 10.5 KB (added by , 5 years ago) |
---|
-
src/org/openstreetmap/josm/data/validation/tests/ConnectivityRelations.java
70 70 * Convert the connectivity tag into a map of values 71 71 * 72 72 * @param relation A relation with a {@code connectivity} tag. 73 * @return A Map in the form of {@code Map<Lane From, Map<Lane To, Optional>>} May contain nulls when errors are encountered 73 * @return A Map in the form of {@code Map<Lane From, Map<Lane To, Optional>>} May contain nulls when errors are encountered, 74 * empty collection if {@code connectivity} tag contains unusual values 74 75 */ 75 76 public static Map<Integer, Map<Integer, Boolean>> parseConnectivityTag(Relation relation) { 76 String cnTag = relation.get(CONNECTIVITY_TAG);77 if (cnTag == null ) {77 final String cnTag = relation.get(CONNECTIVITY_TAG); 78 if (cnTag == null || cnTag.isEmpty()) { 78 79 return Collections.emptyMap(); 79 80 } 80 81 final String joined = cnTag.replace("bw", Integer.toString(BW)); 81 82 82 83 final Map<Integer, Map<Integer, Boolean>> result = new HashMap<>(); 83 String[] lanes = joined.split("\\|", -1); 84 for (int i = 0; i < lanes.length; i++) { 85 final String[] lane = lanes[i].split(":", -1); 84 String[] lanePairs = joined.split("\\|", -1); 85 for (final String lanePair : lanePairs) { 86 final String[] lane = lanePair.split(":", -1); 87 if (lane.length < 2) 88 return Collections.emptyMap(); 86 89 int laneNumber; 87 //Ignore connections from bw, since we cannot derive a lane number from bw 88 if (!"bw".equals(lane[0])) { 90 try { 89 91 laneNumber = Integer.parseInt(lane[0].trim()); 90 } else{91 laneNumber = BW;92 } catch (NumberFormatException e) { 93 return Collections.emptyMap(); 92 94 } 95 93 96 Map<Integer, Boolean> connections = new HashMap<>(); 94 97 String[] toLanes = TO_LANE_PATTERN.split(lane[1], -1); 95 for (int j = 0; j < toLanes.length; j++) { 96 String toLane = toLanes[j].trim(); 98 for (String toLane : toLanes) { 97 99 try { 98 100 if (OPTIONAL_LANE_PATTERN.matcher(toLane).matches()) { 99 101 toLane = toLane.replace("(", "").replace(")", "").trim(); 100 if (!"bw".equals(toLane)) { 101 connections.put(Integer.parseInt(toLane), Boolean.TRUE); 102 } else 103 connections.put(BW, Boolean.TRUE); 102 connections.put(Integer.parseInt(toLane), Boolean.TRUE); 104 103 } else { 105 if (!toLane.contains("bw")) { 106 connections.put(Integer.parseInt(toLane), Boolean.FALSE); 107 } else { 108 connections.put(BW, Boolean.FALSE); 109 } 104 connections.put(Integer.parseInt(toLane), Boolean.FALSE); 110 105 } 111 106 } catch (NumberFormatException e) { 112 107 if (MISSING_COMMA_PATTERN.matcher(toLane).matches()) { 113 connections.put(null, true);108 connections.put(null, Boolean.TRUE); 114 109 } else { 115 110 connections.put(null, null); 116 111 } … … 128 123 errors.add(TestError.builder(this, Severity.WARNING, NO_CONNECTIVITY_TAG) 129 124 .message(tr("Connectivity relation without connectivity tag")).primitives(r).build()); 130 125 } else if (!r.hasIncompleteMembers()) { 131 boolean badRole = checkForBadRole(r); 132 boolean missingRole = checkForMissingRole(r); 133 if (!badRole && !missingRole) { 134 Map<String, Integer> roleLanes = checkForInconsistentLanes(r); 135 checkForImpliedConnectivity(r, roleLanes); 126 Map<Integer, Map<Integer, Boolean>> connTagLanes = parseConnectivityTag(r); 127 if (connTagLanes.isEmpty()) { 128 errors.add(TestError.builder(this, Severity.ERROR, MALFORMED_CONNECTIVITY_TAG) 129 .message(tr("Connectivity tag contains unusual data")).primitives(r).build()); 130 } else { 131 boolean badRole = checkForBadRole(r); 132 boolean missingRole = checkForMissingRole(r); 133 if (!badRole && !missingRole) { 134 Map<String, Integer> roleLanes = checkForInconsistentLanes(r, connTagLanes); 135 checkForImpliedConnectivity(r, roleLanes, connTagLanes); 136 } 136 137 } 137 138 } 138 139 } … … 142 143 * Compare lane tags of members to values in the {@code connectivity} tag of the relation 143 144 * 144 145 * @param relation A relation with a {@code connectivity} tag. 146 * @param connTagLanes result of {@link ConnectivityRelations#parseConnectivityTag(Relation)} 145 147 * @return A Map in the form of {@code Map<Role, Lane Count>} 146 148 */ 147 private Map<String, Integer> checkForInconsistentLanes(Relation relation ) {149 private Map<String, Integer> checkForInconsistentLanes(Relation relation, Map<Integer, Map<Integer, Boolean>> connTagLanes) { 148 150 StringBuilder lanelessRoles = new StringBuilder(); 149 151 int lanelessRolesCount = 0; 150 152 // Lane count from connectivity tag 151 Map<Integer, Map<Integer, Boolean>> connTagLanes = parseConnectivityTag(relation); 153 Map<String, Integer> roleLanes = new HashMap<>(); 154 if (connTagLanes.isEmpty()) 155 return roleLanes; 156 152 157 // If the ways involved in the connectivity tag are assuming a standard 2-way bi-directional highway 153 158 boolean defaultLanes = true; 154 159 for (Entry<Integer, Map<Integer, Boolean>> thisEntry : connTagLanes.entrySet()) { … … 164 169 } 165 170 } 166 171 // Lane count from member tags 167 Map<String, Integer> roleLanes = new HashMap<>();168 172 for (RelationMember rM : relation.getMembers()) { 169 173 // Check lanes 170 174 if (rM.getType() == OsmPrimitiveType.WAY) { … … 186 190 } 187 191 } 188 192 189 if (!laneCounts. equals(Collections.emptyList())) {193 if (!laneCounts.isEmpty()) { 190 194 maxLaneCount = Collections.max(laneCounts); 191 195 roleLanes.put(rM.getRole(), (int) maxLaneCount); 192 196 } else { 193 String addString = "'" + rM.getRole() + "'";194 StringBuilder sb = new StringBuilder(addString);195 197 if (lanelessRoles.length() > 0) { 196 sb.insert(0," and ");198 lanelessRoles.append(" and "); 197 199 } 198 lanelessRoles.append( sb.toString());200 lanelessRoles.append('\'').append(rM.getRole()).append('\''); 199 201 lanelessRolesCount++; 200 202 } 201 203 } … … 202 204 } 203 205 } 204 206 205 if (lanelessRoles. toString().isEmpty()) {207 if (lanelessRoles.length() == 0) { 206 208 boolean fromCheck = roleLanes.get(FROM) < Collections 207 209 .max(connTagLanes.entrySet(), Comparator.comparingInt(Map.Entry::getKey)).getKey(); 208 210 boolean toCheck = false; … … 242 244 * 243 245 * @param relation A relation with a {@code connectivity} tag. 244 246 * @param roleLanes The lane counts for each relation role 247 * @param connTagLanes result of {@link ConnectivityRelations#parseConnectivityTag(Relation)} 245 248 */ 246 private void checkForImpliedConnectivity(Relation relation, Map<String, Integer> roleLanes ) {247 Map<Integer, Map<Integer, Boolean>> connTagLanes = parseConnectivityTag(relation);249 private void checkForImpliedConnectivity(Relation relation, Map<String, Integer> roleLanes, 250 Map<Integer, Map<Integer, Boolean>> connTagLanes) { 248 251 // Don't flag connectivity as already implied when: 249 252 // - Lane counts are different on the roads 250 253 // - Placement tags convey the connectivity -
test/unit/org/openstreetmap/josm/data/validation/tests/ConnectivityRelationsTest.java
2 2 package org.openstreetmap.josm.data.validation.tests; 3 3 4 4 import org.junit.Assert; 5 import org.junit.jupiter.api.BeforeAll; 5 6 import org.junit.jupiter.api.BeforeEach; 6 7 import org.junit.jupiter.api.Test; 7 8 import org.openstreetmap.josm.JOSMFixture; … … 19 20 class ConnectivityRelationsTest { 20 21 private ConnectivityRelations check; 21 22 private static final String CONNECTIVITY = "connectivity"; 23 22 24 /** 23 25 * Setup test. 24 *25 * @throws Exception if an error occurs26 26 */ 27 @BeforeAll 28 public static void setUp() { 29 JOSMFixture.createUnitTestFixture().init(); 30 } 31 27 32 @BeforeEach 28 public void setUp() throws Exception { 29 JOSMFixture.createUnitTestFixture().init(); 33 public void setUpCheck() throws Exception { 30 34 check = new ConnectivityRelations(); 31 35 } 32 36 … … 85 89 Assert.assertEquals(++expectedFailures, check.getErrors().size()); 86 90 } 87 91 92 /** 93 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/201821">Bug #20182</a>. 94 * @throws Exception if an error occurs 95 */ 96 @Test 97 void testTicket20182() throws Exception { 98 Relation relation = createDefaultTestRelation(); 99 check.visit(relation); 100 int expectedFailures = 0; 101 102 Assert.assertEquals(expectedFailures, check.getErrors().size()); 103 104 relation.put(CONNECTIVITY, "left_turn"); 105 check.visit(relation); 106 Assert.assertEquals(++expectedFailures, check.getErrors().size()); 107 108 relation.put(CONNECTIVITY, "1"); 109 check.visit(relation); 110 Assert.assertEquals(++expectedFailures, check.getErrors().size()); 111 } 88 112 }