Changeset 8265 in josm
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
r8130 r8265 141 141 } 142 142 143 /** 144 * Represents a fix to a validation test. The fixing {@link Command} can be obtained by {@link #createCommand(OsmPrimitive, Selector)}. 145 */ 146 static abstract class FixCommand { 147 /** 148 * Creates the fixing {@link Command} for the given primitive. The {@code matchingSelector} is used to 149 * evaluate placeholders (cf. {@link org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker.TagCheck#insertArguments(Selector, String)}). 150 */ 151 abstract Command createCommand(final OsmPrimitive p, final Selector matchingSelector); 152 153 private static void checkObject(final Object obj) { 154 CheckParameterUtil.ensureThat(obj instanceof Expression || obj instanceof String, "instance of Exception or String expected, but got " + obj); 155 } 156 157 /** 158 * Evaluates given object as {@link Expression} or {@link String} on the matched {@link OsmPrimitive} and {@code matchingSelector}. 159 */ 160 private static String evaluateObject(final Object obj, final OsmPrimitive p, final Selector matchingSelector) { 161 final String s; 162 if (obj instanceof Expression) { 163 s = (String) ((Expression) obj).evaluate(new Environment().withPrimitive(p)); 164 } else if (obj instanceof String) { 165 s = (String) obj; 166 } else { 167 return null; 168 } 169 return TagCheck.insertArguments(matchingSelector, s); 170 } 171 172 /** 173 * Creates a fixing command which executes a {@link ChangePropertyCommand} on the specified tag. 174 */ 175 static FixCommand fixAdd(final Object obj) { 176 checkObject(obj); 177 return new FixCommand() { 178 @Override 179 Command createCommand(OsmPrimitive p, Selector matchingSelector) { 180 final Tag tag = Tag.ofString(evaluateObject(obj, p, matchingSelector)); 181 return new ChangePropertyCommand(p, tag.getKey(), tag.getValue()); 182 } 183 184 @Override 185 public String toString() { 186 return "fixAdd: " + obj; 187 } 188 }; 189 190 } 191 192 /** 193 * Creates a fixing command which executes a {@link ChangePropertyCommand} to delete the specified key. 194 */ 195 static FixCommand fixRemove(final Object obj) { 196 checkObject(obj); 197 return new FixCommand() { 198 @Override 199 Command createCommand(OsmPrimitive p, Selector matchingSelector) { 200 final String key = evaluateObject(obj, p, matchingSelector); 201 return new ChangePropertyCommand(p, key, ""); 202 } 203 204 @Override 205 public String toString() { 206 return "fixRemove: " + obj; 207 } 208 }; 209 } 210 211 /** 212 * Creates a fixing command which executes a {@link ChangePropertyKeyCommand} on the specified keys. 213 */ 214 static FixCommand fixChangeKey(final String oldKey, final String newKey) { 215 return new FixCommand() { 216 @Override 217 Command createCommand(OsmPrimitive p, Selector matchingSelector) { 218 return new ChangePropertyKeyCommand(p, oldKey, newKey); 219 } 220 221 @Override 222 public String toString() { 223 return "fixChangeKey: " + oldKey + " => " + newKey; 224 } 225 }; 226 } 227 } 228 143 229 final MultiMap<String, TagCheck> checks = new MultiMap<>(); 144 230 145 231 static class TagCheck implements Predicate<OsmPrimitive> { 146 232 protected final GroupedMapCSSRule rule; 147 protected final List<PrimitiveToTag> change = new ArrayList<>(); 148 protected final Map<String, String> keyChange = new LinkedHashMap<>(); 233 protected final List<FixCommand> fixCommands = new ArrayList<>(); 149 234 protected final List<String> alternatives = new ArrayList<>(); 150 235 protected final Map<Instruction.AssignmentInstruction, Severity> errors = new HashMap<>(); … … 155 240 TagCheck(GroupedMapCSSRule rule) { 156 241 this.rule = rule; 157 }158 159 /**160 * A function mapping the matched {@link OsmPrimitive} to a {@link Tag}.161 */162 abstract static class PrimitiveToTag implements Utils.Function<OsmPrimitive, Tag> {163 164 private PrimitiveToTag() {165 // Hide implicit public constructor for utility class166 }167 168 /**169 * Creates a new mapping from an {@code MapCSS} object.170 * In case of an {@link Expression}, that is evaluated on the matched {@link OsmPrimitive}.171 * In case of a {@link String}, that is "compiled" to a {@link Tag} instance.172 */173 static PrimitiveToTag ofMapCSSObject(final Object obj, final boolean keyOnly) {174 if (obj instanceof Expression) {175 return new PrimitiveToTag() {176 @Override177 public Tag apply(OsmPrimitive p) {178 final String s = (String) ((Expression) obj).evaluate(new Environment().withPrimitive(p));179 return keyOnly? new Tag(s) : Tag.ofString(s);180 }181 };182 } else if (obj instanceof String) {183 final Tag tag = keyOnly ? new Tag((String) obj) : Tag.ofString((String) obj);184 return new PrimitiveToTag() {185 @Override186 public Tag apply(OsmPrimitive ignore) {187 return tag;188 }189 };190 } else {191 return null;192 }193 }194 242 } 195 243 … … 233 281 } 234 282 } else if ("fixAdd".equals(ai.key)) { 235 final PrimitiveToTag toTag = PrimitiveToTag.ofMapCSSObject(ai.val, false); 236 if (toTag != null) { 237 check.change.add(toTag); 238 } else { 239 Main.warn("Invalid value for "+ai.key+": "+ai.val); 240 } 283 check.fixCommands.add(FixCommand.fixAdd(ai.val)); 241 284 } else if ("fixRemove".equals(ai.key)) { 242 285 CheckParameterUtil.ensureThat(!(ai.val instanceof String) || !(val != null && val.contains("=")), 243 286 "Unexpected '='. Please only specify the key to remove!"); 244 final PrimitiveToTag toTag = PrimitiveToTag.ofMapCSSObject(ai.val, true); 245 if (toTag != null) { 246 check.change.add(toTag); 247 } else { 248 Main.warn("Invalid value for "+ai.key+": "+ai.val); 249 } 287 check.fixCommands.add(FixCommand.fixRemove(ai.val)); 250 288 } else if ("fixChangeKey".equals(ai.key) && val != null) { 251 289 CheckParameterUtil.ensureThat(val.contains("=>"), "Separate old from new key by '=>'!"); 252 290 final String[] x = val.split("=>", 2); 253 check. keyChange.put(Tag.removeWhiteSpaces(x[0]), Tag.removeWhiteSpaces(x[1]));291 check.fixCommands.add(FixCommand.fixChangeKey(Tag.removeWhiteSpaces(x[0]), Tag.removeWhiteSpaces(x[1]))); 254 292 } else if ("fixDeleteObject".equals(ai.key) && val != null) { 255 293 CheckParameterUtil.ensureThat(val.equals("this"), "fixDeleteObject must be followed by 'this'"); … … 408 446 */ 409 447 Command fixPrimitive(OsmPrimitive p) { 410 if ( change.isEmpty() && keyChange.isEmpty() && !deletion) {448 if (fixCommands.isEmpty() && !deletion) { 411 449 return null; 412 450 } 413 451 final Selector matchingSelector = whichSelectorMatchesPrimitive(p); 414 452 Collection<Command> cmds = new LinkedList<>(); 415 for (PrimitiveToTag toTag : change) { 416 final Tag tag = toTag.apply(p); 417 final String key = insertArguments(matchingSelector, tag.getKey()); 418 final String value = insertArguments(matchingSelector, tag.getValue()); 419 cmds.add(new ChangePropertyCommand(p, key, value)); 420 } 421 for (Map.Entry<String, String> i : keyChange.entrySet()) { 422 final String oldKey = insertArguments(matchingSelector, i.getKey()); 423 final String newKey = insertArguments(matchingSelector, i.getValue()); 424 cmds.add(new ChangePropertyKeyCommand(p, oldKey, newKey)); 453 for (FixCommand fixCommand : fixCommands) { 454 cmds.add(fixCommand.createCommand(p, matchingSelector)); 425 455 } 426 456 if (deletion) { -
trunk/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
r7937 r8265 8 8 9 9 import java.io.StringReader; 10 import java.util.Iterator; 10 11 import java.util.LinkedHashSet; 11 12 import java.util.List; … … 17 18 import org.openstreetmap.josm.Main; 18 19 import org.openstreetmap.josm.command.ChangePropertyCommand; 20 import org.openstreetmap.josm.command.ChangePropertyKeyCommand; 21 import org.openstreetmap.josm.command.Command; 22 import org.openstreetmap.josm.command.PseudoCommand; 23 import org.openstreetmap.josm.command.SequenceCommand; 19 24 import org.openstreetmap.josm.data.osm.Node; 20 import org.openstreetmap.josm.data.osm.Tag; 25 import org.openstreetmap.josm.data.osm.OsmPrimitive; 26 import org.openstreetmap.josm.data.osm.OsmUtils; 21 27 import org.openstreetmap.josm.data.validation.Severity; 22 28 import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker.TagCheck; … … 49 55 assertThat(check, notNullValue()); 50 56 assertThat(check.getDescription(null), is("{0.key}=null is deprecated")); 51 assertThat(check. change.get(0).apply(null), is(new Tag("{0.key}")));52 assertThat(check. change.get(1).apply(null), is(new Tag("natural", "wetland")));53 assertThat(check. change.get(2).apply(null), is(new Tag("wetland", "marsh")));57 assertThat(check.fixCommands.get(0).toString(), is("fixRemove: {0.key}")); 58 assertThat(check.fixCommands.get(1).toString(), is("fixAdd: natural=wetland")); 59 assertThat(check.fixCommands.get(2).toString(), is("fixAdd: wetland=marsh")); 54 60 final Node n1 = new Node(); 55 61 n1.put("natural", "marsh"); … … 65 71 assertThat(MapCSSTagChecker.TagCheck.insertArguments(check.rule.selectors.get(0), "The key is {0.key} and the value is {0.value}"), 66 72 is("The key is natural and the value is marsh")); 73 } 74 75 @Test 76 public void test10913() throws Exception { 77 final OsmPrimitive p = OsmUtils.createPrimitive("way highway=tertiary construction=yes"); 78 final TagCheck check = TagCheck.readMapCSS(new StringReader("way {" + 79 "throwError: \"error\";" + 80 "fixChangeKey: \"highway => construction\";\n" + 81 "fixAdd: \"highway=construction\";\n" + 82 "}")).get(0); 83 final Command command = check.fixPrimitive(p); 84 assertThat(command instanceof SequenceCommand, is(true)); 85 final Iterator<PseudoCommand> it = command.getChildren().iterator(); 86 assertThat(it.next() instanceof ChangePropertyKeyCommand, is(true)); 87 assertThat(it.next() instanceof ChangePropertyCommand, is(true)); 67 88 } 68 89
Note:
See TracChangeset
for help on using the changeset viewer.