Ticket #21930: street-parking-keys-with-conditional.diff
| File street-parking-keys-with-conditional.diff, 13.3 KB (added by , 3 years ago) |
|---|
-
src/org/openstreetmap/josm/data/validation/tests/ConditionalKeys.java
6 6 import java.util.ArrayList; 7 7 import java.util.Arrays; 8 8 import java.util.Collection; 9 import java.util.HashMap; 9 10 import java.util.HashSet; 10 11 import java.util.List; 12 import java.util.Map; 11 13 import java.util.Set; 12 14 import java.util.regex.Matcher; 13 15 import java.util.regex.Pattern; 16 import java.util.stream.Collectors; 17 import java.util.stream.Stream; 14 18 15 19 import org.openstreetmap.josm.data.osm.OsmPrimitive; 16 20 import org.openstreetmap.josm.data.validation.Severity; … … 26 30 27 31 private final OpeningHourTest openingHourTest = new OpeningHourTest(); 28 32 private static final Set<String> RESTRICTION_TYPES = new HashSet<>(Arrays.asList("oneway", "toll", "noexit", "maxspeed", "minspeed", 29 "maxstay", "maxweight", "maxaxleload", "maxheight", "maxwidth", "maxlength", "overtaking", "maxgcweight", "maxgcweightrating", 30 "fee", "restriction", "interval", "duration", "dog", "maxweightrating")); 33 "maxweight", "maxaxleload", "maxheight", "maxwidth", "maxlength", "overtaking", "maxgcweight", "maxgcweightrating", 34 "interval", "duration", "dog", "maxweightrating")); 35 36 private static final Set<String> PARKING_RESTRICTION_TYPES = new HashSet<>(Arrays.asList("authentication:disc", 37 "authentication:ticket", "charge", "fee", "maxstay", "restriction", "restriction:reason")); 38 39 private static final Set<String> ALL_RESTRICTION_TYPES = Stream.concat(RESTRICTION_TYPES.stream(), 40 PARKING_RESTRICTION_TYPES.stream()).collect(Collectors.toSet()); 41 31 42 private static final Set<String> RESTRICTION_VALUES = new HashSet<>(Arrays.asList("yes", "official", "designated", "destination", 32 43 "delivery", "customers", "permissive", "private", "agricultural", "forestry", "no")); 44 45 /** 46 * <a href="http://wiki.openstreetmap.org/wiki/Key:access#Transport_mode_restrictions">transport access mode restriction</a> 47 */ 33 48 private static final Set<String> TRANSPORT_MODES = new HashSet<>(Arrays.asList("access", "foot", "ski", "inline_skates", "ice_skates", 34 49 "horse", "vehicle", "bicycle", "carriage", "trailer", "caravan", "motor_vehicle", "motorcycle", "moped", "mofa", 35 50 "motorcar", "motorhome", "psv", "bus", "taxi", "tourist_bus", "goods", "hgv", "agricultural", "atv", "snowmobile", … … 36 51 "hgv_articulated", "ski:nordic", "ski:alpine", "ski:telemark", "coach", "golf_cart" 37 52 /*,"minibus","share_taxi","hov","car_sharing","emergency","hazmat","disabled"*/)); 38 53 54 private static final Set<String> DIRECTIONS = new HashSet<>(Arrays.asList("forward", "backward", "both_ways")); 55 56 private static final Set<String> SIDES = new HashSet<>(Arrays.asList("left", "right", "both")); 57 58 private static final Map<String, KeyCharacteristic> KNOWN_CONDITIONAL_KEYS = buildKnownKeys(); 59 39 60 private static final Pattern CONDITIONAL_PATTERN; 40 61 static { 41 62 final String part = Pattern.compile("([^@\\p{Space}][^@]*?)" … … 56 77 openingHourTest.initialize(); 57 78 } 58 79 59 /** 60 * Check if the key is a key for an access restriction 61 * @param part The key (or the restriction part of it, e.g. for lanes) 62 * @return <code>true</code> if it is a restriction 63 */ 64 public static boolean isRestrictionType(String part) { 65 return RESTRICTION_TYPES.contains(part); 80 private enum KeyCharacteristic { 81 ACCESS, 82 OTHER 66 83 } 67 84 85 private static Map<String, KeyCharacteristic> buildKnownKeys() { 86 // <restriction-type>[:<transportation mode>][:<direction>]:conditional 87 Map<String, KeyCharacteristic> knownKeys = new HashMap<>(); 88 for (String restrictionType : ALL_RESTRICTION_TYPES) { 89 knownKeys.put(String.format("%s:conditional", restrictionType), KeyCharacteristic.OTHER); 90 for (String mode : TRANSPORT_MODES) { 91 knownKeys.put(String.format("%s:%s:conditional", restrictionType, mode), KeyCharacteristic.OTHER); 92 for (String direction : DIRECTIONS) { 93 knownKeys.put(String.format("%s:%s:%s:conditional", restrictionType, mode, direction), 94 KeyCharacteristic.OTHER); 95 } 96 } 97 for (String direction : DIRECTIONS) { 98 knownKeys.put(String.format("%s:%s:conditional", restrictionType, direction), KeyCharacteristic.OTHER); 99 } 100 } 101 // <transportation mode> [:<direction>]:conditional 102 for (String mode : TRANSPORT_MODES) { 103 knownKeys.put(String.format("%s:conditional", mode), KeyCharacteristic.ACCESS); 104 for (String direction : DIRECTIONS) { 105 knownKeys.put(String.format("%s:%s:conditional", mode, direction), KeyCharacteristic.ACCESS); 106 } 107 } 108 // parking:<side>:<restriction-type>[:<transportation mode] :conditional 109 for (String side : SIDES) { 110 for (String restrictionType : PARKING_RESTRICTION_TYPES) { 111 knownKeys.put(String.format("parking:%s:%s:conditional", side, restrictionType), 112 KeyCharacteristic.OTHER); 113 for (String mode : TRANSPORT_MODES) { 114 knownKeys.put(String.format("parking:%s:%s:%s:conditional", side, restrictionType, mode), 115 KeyCharacteristic.OTHER); 116 } 117 } 118 } 119 // parking:<side> :<transportation mode> :conditional 120 for (String side : SIDES) { 121 for (String mode : TRANSPORT_MODES) { 122 knownKeys.put(String.format("parking:%s:%s:conditional", side, mode), KeyCharacteristic.ACCESS); 123 } 124 } 125 return knownKeys; 126 } 127 68 128 /** 69 129 * Check if the value is a valid restriction value 70 130 * @param part The value … … 75 135 } 76 136 77 137 /** 78 * Checks if the key denotes a79 * <a href="http://wiki.openstreetmap.org/wiki/Key:access#Transport_mode_restrictions">transport access mode restriction</a>80 * @param part The key (or the restriction part of it, e.g. for lanes)81 * @return <code>true</code> if it is a restriction82 */83 public static boolean isTransportationMode(String part) {84 return TRANSPORT_MODES.contains(part);85 }86 87 /**88 * Check if a key part is a valid direction89 * @param part The part of the key90 * @return <code>true</code> if it is a direction91 */92 public static boolean isDirection(String part) {93 return "forward".equals(part) || "backward".equals(part);94 }95 96 /**97 138 * Checks if a given key is a valid access key 98 139 * @param key The conditional key 99 140 * @return <code>true</code> if the key is valid 100 141 */ 101 142 public boolean isKeyValid(String key) { 102 // <restriction-type>[:<transportation mode>][:<direction>]:conditional 103 // -- or -- <transportation mode> [:<direction>]:conditional 104 if (!key.endsWith(":conditional")) { 105 return false; 106 } 107 final String[] parts = key.replace(":conditional", "").split(":", -1); 108 return isKeyValid3Parts(parts) || isKeyValid1Part(parts) || isKeyValid2Parts(parts); 143 return KNOWN_CONDITIONAL_KEYS.containsKey(key); 109 144 } 110 145 111 private static boolean isKeyValid3Parts(String... parts) {112 return parts.length == 3 && isRestrictionType(parts[0]) && isTransportationMode(parts[1]) && isDirection(parts[2]);113 }114 115 private static boolean isKeyValid2Parts(String... parts) {116 return parts.length == 2 && ((isRestrictionType(parts[0]) && (isTransportationMode(parts[1]) || isDirection(parts[1])))117 || (isTransportationMode(parts[0]) && isDirection(parts[1])));118 }119 120 private static boolean isKeyValid1Part(String... parts) {121 return parts.length == 1 && (isRestrictionType(parts[0]) || isTransportationMode(parts[0]));122 }123 124 146 /** 125 147 * Check if a value is valid 126 148 * @param key The key the value is for … … 195 217 try { 196 218 for (final ConditionalValue conditional : ConditionalValue.parse(value)) { 197 219 // validate restriction value 198 if (isTransportationMode(key.split(":", -1)[0]) && !isRestrictionValue(conditional.restrictionValue)) { 220 KeyCharacteristic keyCharacteristic = KNOWN_CONDITIONAL_KEYS.get(key); 221 if (keyCharacteristic == KeyCharacteristic.ACCESS && !isRestrictionValue(conditional.restrictionValue)) { 199 222 return tr("{0} is not a valid restriction value", conditional.restrictionValue); 200 223 } 201 224 // validate opening hour if the value contains an hour (heuristic) -
test/unit/org/openstreetmap/josm/data/validation/tests/ConditionalKeysTest.java
7 7 import org.junit.jupiter.api.BeforeEach; 8 8 import org.junit.jupiter.api.Test; 9 9 import org.junit.jupiter.api.extension.RegisterExtension; 10 import org.junit.jupiter.params.ParameterizedTest; 11 import org.junit.jupiter.params.provider.ValueSource; 10 12 import org.openstreetmap.josm.testutils.JOSMTestRules; 11 13 12 14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; … … 35 37 } 36 38 37 39 /** 38 * Unit test of {@link ConditionalKeys#isKeyValid}.40 * Unit tests of {@link ConditionalKeys#isKeyValid}. 39 41 */ 40 @Test 41 void testKeyValid() { 42 assertTrue(test.isKeyValid("dog:conditional")); 43 assertTrue(test.isKeyValid("maxspeed:conditional")); 44 assertTrue(test.isKeyValid("motor_vehicle:conditional")); 45 assertTrue(test.isKeyValid("bicycle:conditional")); 46 assertTrue(test.isKeyValid("overtaking:hgv:conditional")); 47 assertTrue(test.isKeyValid("maxspeed:hgv:backward:conditional")); 48 assertTrue(test.isKeyValid("oneway:backward:conditional")); 49 assertTrue(test.isKeyValid("fee:conditional")); 50 assertTrue(test.isKeyValid("restriction:conditional")); 51 assertFalse(test.isKeyValid("maxspeed:hgv:conditional:backward")); 42 @ValueSource(strings = { "dog:conditional", "maxspeed:conditional", "overtaking:hgv:conditional", 43 "maxspeed:hgv:backward:conditional", "oneway:backward:conditional", "fee:conditional", 44 "restriction:conditional" }) 45 @ParameterizedTest 46 void testKeyIsValid(String key) { 47 assertTrue(test.isKeyValid(key)); 52 48 } 53 49 50 @ValueSource(strings = { "bicycle:conditional", "motor_vehicle:conditional", "ski:alpine:conditional" }) 51 @ParameterizedTest 52 void testTransportationModeKeyIsValid(String key) { 53 assertTrue(test.isKeyValid(key)); 54 } 55 56 @ValueSource(strings = { "parking:both:maxstay:conditional", "parking:left:access:conditional", 57 "parking:right:restriction:conditional", "parking:right:restriction:reason:conditional" }) 58 @ParameterizedTest 59 void testParkingRestrictionBySideKeyIsValid(String key) { 60 assertTrue(test.isKeyValid(key)); 61 } 62 63 @ValueSource(strings = { "parking:both:maxstay:hgv:conditional", 64 "parking:right:authentication:ticket:conditional" }) 65 @ParameterizedTest 66 void testParkingRestrictionBySideWithModeKeyIsValid(String key) { 67 assertTrue(test.isKeyValid(key)); 68 } 69 70 @ValueSource(strings = { ":conditional", // no base key 71 "maxspeed:hgv:conditional:backward", // direction must be before :conditional 72 "parking:forward:maxstay:conditional", // parking side must be both, left or right 73 "parking:both:fee:forward:conditional", // parking can not have a direction 74 "parking:left:oneway:conditional" // oneway is not a parking restriction 75 }) 76 @ParameterizedTest 77 void testKeyIsInvalid(String key) { 78 assertFalse(test.isKeyValid(key)); 79 } 80 54 81 /** 55 82 * Unit test of {@link ConditionalKeys#isValueValid}. 56 83 */ … … 65 92 assertTrue(test.isValueValid("maxspeed:conditional", "120 @ (06:00-20:00); 100 @ (22:00-06:00)")); 66 93 assertTrue(test.isValueValid("motor_vehicle:conditional", "delivery @ (Mo-Fr 06:00-11:00,17:00-19:00;Sa 03:30-19:00)")); 67 94 assertTrue(test.isValueValid("motor_vehicle:conditional", "no @ (10:00-18:00 AND length>5)")); 95 assertTrue(test.isValueValid("parking:right:motor_vehicle:conditional", "no @ (10:00-18:00 AND length>5)")); 68 96 assertFalse(test.isValueValid("motor_vehicle:conditional", "foo @ (10:00-18:00 AND length>5)")); 97 assertFalse(test.isValueValid("parking:right:motor_vehicle:conditional", "foo @ (10:00-18:00 AND length>5)")); 69 98 assertFalse(test.isValueValid("motor_vehicle:conditional", "no @ (10:00until18:00 AND length>5)")); 70 99 assertTrue(test.isValueValid("maxspeed:hgv:conditional", "60 @ (weight>7.5)")); 71 100 assertTrue(test.isValueValid("restriction:conditional", "no_left_turn @ (Mo-Fr 16:00-18:00)"));
