Changeset 36235 in osm for applications/editors/josm/plugins
- Timestamp:
- 2024-04-03T17:47:14+02:00 (8 months ago)
- Location:
- applications/editors/josm/plugins/reverter/test
- Files:
-
- 10 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/reverter/test/data/regress/README.md
r36233 r36235 11 11 ``` 12 12 13 **Warning**: JOSM will not copy deleted objects to clipboard. 14 13 15 Once you have the list, you can run the following command: 14 16 ```shell 15 17 # Note: `pbpaste` is for mac, `xclip -selection clipboard -o` is for x11 linux, and `wl-paste` (from `wl-clipboard`) is for linux wayland 16 18 $ wl-paste | \ 17 awk '{print "https://api.openstreetmap.org/api/0.6/ $1/" $2 "/history.json" " -o " $1 "_" $2 ".json"}' | \19 awk '{print "https://api.openstreetmap.org/api/0.6/" $1 "/" $2 "/history.json" " -o " $1 "_" $2 ".json"}' | \ 18 20 xargs curl -L 19 21 $ jq -s '.[0].elements=([.[].elements]|flatten)|.[0]' node_*.json > nodes.json -
applications/editors/josm/plugins/reverter/test/unit/reverter/ChangesetReverterTest.java
r36233 r36235 3 3 4 4 import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; 5 import static org.junit.jupiter.api.Assertions.assertAll; 5 6 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 6 7 import static org.junit.jupiter.api.Assertions.assertEquals; … … 14 15 import java.nio.file.Paths; 15 16 import java.util.Arrays; 17 import java.util.Collection; 16 18 import java.util.Collections; 17 19 import java.util.HashMap; … … 23 25 import java.util.stream.Collectors; 24 26 27 import javax.swing.JOptionPane; 28 25 29 import org.junit.jupiter.api.Test; 26 30 import org.junit.jupiter.api.extension.RegisterExtension; … … 30 34 import org.openstreetmap.josm.data.UndoRedoHandler; 31 35 import org.openstreetmap.josm.data.osm.DataSet; 36 import org.openstreetmap.josm.data.osm.Node; 37 import org.openstreetmap.josm.data.osm.OsmPrimitive; 32 38 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 33 39 import org.openstreetmap.josm.data.osm.PrimitiveId; 40 import org.openstreetmap.josm.data.osm.Relation; 34 41 import org.openstreetmap.josm.data.osm.SimplePrimitiveId; 35 42 import org.openstreetmap.josm.data.osm.Way; … … 43 50 import org.openstreetmap.josm.testutils.annotations.Main; 44 51 import org.openstreetmap.josm.testutils.annotations.Projection; 52 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker; 45 53 import org.openstreetmap.josm.tools.JosmRuntimeException; 46 54 import org.openstreetmap.josm.tools.Logging; … … 72 80 class ChangesetReverterTest { 73 81 @RegisterExtension 74 static WireMockExtension wireMockExtension = WireMockExtension.newInstance() 75 .options(wireMockConfig().dynamicPort().dynamicHttpsPort().extensions(new MultiplePrimitiveTransformer())) 82 static WireMockExtension wireMockExtension = WireMockExtension.newInstance().options( 83 wireMockConfig().dynamicPort().dynamicHttpsPort() 84 .extensions(new MultiplePrimitiveTransformer(), new PrimitiveTransformer())) 76 85 .build(); 77 86 … … 82 91 void testTicket22520(WireMockRuntimeInfo wireMockRuntimeInfo) throws ExecutionException, InterruptedException { 83 92 wireMockRuntimeInfo.getWireMock().loadMappingsFrom(TestUtils.getRegressionDataDir(22520)); 84 wireMockRuntimeInfo.getWireMock().register(WireMock.get(WireMock.urlPathMatching("/0.6/nodes")).willReturn(WireMock.aResponse().withTransformer("MultiplePrimitiveTransformer", "ticket", 22520))); 85 wireMockRuntimeInfo.getWireMock().register(WireMock.get(WireMock.urlPathMatching("/0.6/relations")).willReturn(WireMock.aResponse().withTransformer("MultiplePrimitiveTransformer", "ticket", 22520))); 86 wireMockRuntimeInfo.getWireMock().register(WireMock.get(WireMock.urlPathMatching("/0.6/ways")).willReturn(WireMock.aResponse().withTransformer("MultiplePrimitiveTransformer", "ticket", 22520))); 93 MultiplePrimitiveTransformer.register(wireMockRuntimeInfo.getWireMock(), 22520); 87 94 Config.getPref().put("osm-server.url", wireMockRuntimeInfo.getHttpBaseUrl()); 88 95 PrimitiveId building = new SimplePrimitiveId(233056719, OsmPrimitiveType.WAY); 89 new DownloadOsmTask().loadUrl(new DownloadParams().withLayerName("testTicket22520"), wireMockRuntimeInfo.getHttpBaseUrl() + "/0.6/way/233056719/3", NullProgressMonitor.INSTANCE).get(); 90 OsmDataLayer layer = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class).stream().filter(l -> "testTicket22520".equals(l.getName())).findFirst().orElse(null); 96 new DownloadOsmTask().loadUrl(new DownloadParams().withLayerName("testTicket22520"), 97 wireMockRuntimeInfo.getHttpBaseUrl() + "/0.6/way/233056719/3", NullProgressMonitor.INSTANCE).get(); 98 OsmDataLayer layer = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class).stream() 99 .filter(l -> "testTicket22520".equals(l.getName())).findFirst().orElse(null); 91 100 assertNotNull(layer); 92 101 layer.getDataSet().setSelected(building); 93 RevertChangesetTask task = new RevertChangesetTask(NullProgressMonitor.INSTANCE, Collections.singletonList(36536612), ChangesetReverter.RevertType.SELECTION_WITH_UNDELETE, true, false); 102 RevertChangesetTask task = new RevertChangesetTask(NullProgressMonitor.INSTANCE, Collections.singletonList(36536612), 103 ChangesetReverter.RevertType.SELECTION_WITH_UNDELETE, true, false); 94 104 assertDoesNotThrow(task::realRun); 95 105 GuiHelper.runInEDTAndWait(() -> { /* Sync threads */ }); … … 104 114 void testTicket23582(WireMockRuntimeInfo wireMockRuntimeInfo) { 105 115 wireMockRuntimeInfo.getWireMock().loadMappingsFrom(TestUtils.getRegressionDataDir(23582)); 106 wireMockRuntimeInfo.getWireMock().register(WireMock.get(WireMock.urlPathMatching("/0.6/nodes")).willReturn(WireMock.aResponse().withTransformer("MultiplePrimitiveTransformer", "ticket", 23582))); 107 wireMockRuntimeInfo.getWireMock().register(WireMock.get(WireMock.urlPathMatching("/0.6/relations")).willReturn(WireMock.aResponse().withTransformer("MultiplePrimitiveTransformer", "ticket", 23582))); 108 wireMockRuntimeInfo.getWireMock().register(WireMock.get(WireMock.urlPathMatching("/0.6/ways")).willReturn(WireMock.aResponse().withTransformer("MultiplePrimitiveTransformer", "ticket", 23582))); 116 MultiplePrimitiveTransformer.register(wireMockRuntimeInfo.getWireMock(), 23582); 109 117 Config.getPref().put("osm-server.url", wireMockRuntimeInfo.getHttpBaseUrl()); 110 118 final RevertChangesetTask task = new RevertChangesetTask(149181932, ChangesetReverter.RevertType.FULL, true, true); … … 117 125 } 118 126 127 @Test 128 void testTicket23584(WireMockRuntimeInfo wireMockRuntimeInfo) { 129 new JOptionPaneSimpleMocker(Collections.singletonMap("Conflicts detected", JOptionPane.OK_OPTION)); 130 wireMockRuntimeInfo.getWireMock().loadMappingsFrom(TestUtils.getRegressionDataDir(23584)); 131 MultiplePrimitiveTransformer.register(wireMockRuntimeInfo.getWireMock(), 23584); 132 PrimitiveTransformer.register(wireMockRuntimeInfo.getWireMock(), 23584); 133 Config.getPref().put("osm-server.url", wireMockRuntimeInfo.getHttpBaseUrl()); 134 final RevertChangesetTask task = new RevertChangesetTask(NullProgressMonitor.INSTANCE, Collections.singleton(97259223), 135 ChangesetReverter.RevertType.FULL, true, true); 136 assertDoesNotThrow(task::realRun); 137 GuiHelper.runInEDTAndWait(() -> { /* Sync UI thread (some actions are taken on this thread which modify primitives) */ }); 138 final DataSet reverted = MainApplication.getLayerManager().getEditDataSet(); 139 final Collection<OsmPrimitive> modified = reverted.allModifiedPrimitives(); 140 assertAll(() -> assertEquals(58, modified.size()), 141 () -> assertEquals(18, modified.stream().filter(Relation.class::isInstance).count()), 142 () -> assertEquals(24, modified.stream().filter(Way.class::isInstance).count()), 143 () -> assertEquals(16, modified.stream().filter(Node.class::isInstance).count())); 144 } 145 119 146 /** 120 * A transformer for the /nodes?node, /ways?ways, and /relations?relations endpoints. This is needed since we don't always do the requests in the same order. 147 * A transformer for `/node/:id/:version`, `way/:id/:version`, and `relation/:id/:version` that will use 148 * the same data as {@link MultiplePrimitiveTransformer}. 149 */ 150 private static class PrimitiveTransformer extends ResponseTransformer { 151 /** 152 * Register the URLs for this transformer 153 * @param wireMock The wiremock object to register stubs for 154 * @param ticket The ticket to get data from 155 */ 156 static void register(WireMock wireMock, int ticket) { 157 wireMock.register(WireMock.get(WireMock.urlPathMatching("/0.6/node/\\d+/?\\d*")).willReturn(WireMock.aResponse() 158 .withTransformer("PrimitiveTransformer", "ticket", ticket))); 159 wireMock.register(WireMock.get(WireMock.urlPathMatching("/0.6/way/\\d+/?\\d*")).willReturn(WireMock.aResponse() 160 .withTransformer("PrimitiveTransformer", "ticket", ticket))); 161 wireMock.register(WireMock.get(WireMock.urlPathMatching("/0.6/relation/\\d+/?\\d*")).willReturn(WireMock.aResponse() 162 .withTransformer("PrimitiveTransformer", "ticket", ticket))); 163 } 164 165 @Override 166 public boolean applyGlobally() { 167 return false; 168 } 169 170 @Override 171 public String getName() { 172 return "PrimitiveTransformer"; 173 } 174 175 @Override 176 public Response transform(Request request, Response response, FileSource files, Parameters parameters) { 177 final int ticket = parameters.getInt("ticket"); 178 final String[] parts = request.getUrl().substring(1).split("/", -1); 179 final int version = Integer.parseInt(parts[3]); 180 final long id = Long.parseLong(parts[2]); 181 final OsmParameterInformation info; 182 switch (parts[1]) { 183 case "node": 184 info = new OsmParameterInformation(OsmPrimitiveType.NODE, id, version); 185 break; 186 case "way": 187 info = new OsmParameterInformation(OsmPrimitiveType.WAY, id, version); 188 break; 189 case "relation": 190 info = new OsmParameterInformation(OsmPrimitiveType.RELATION, id, version); 191 break; 192 default: 193 IllegalArgumentException e = new IllegalArgumentException("No OSM primitive path present"); 194 Logging.error(e); // Log first since wiremock is really bad about propagating and logging exceptions. 195 throw e; 196 } 197 final String body = MultiplePrimitiveTransformer.getReturnXml(ticket, info.type, Collections.singleton(info)); 198 return Response.Builder.like(response).but().body(body).build(); 199 } 200 } 201 202 /** 203 * A transformer for the /nodes?node, /ways?ways, and /relations?relations endpoints. 204 * This is needed since we don't always do the requests in the same order. 121 205 */ 122 206 private static class MultiplePrimitiveTransformer extends ResponseTransformer { 207 208 /** 209 * Register the URLs for this transformer 210 * @param wireMock The wiremock object to register stubs for 211 * @param ticket The ticket to get data from 212 */ 213 static void register(WireMock wireMock, int ticket) { 214 wireMock.register(WireMock.get(WireMock.urlPathMatching("/0.6/nodes")).willReturn(WireMock.aResponse() 215 .withTransformer("MultiplePrimitiveTransformer", "ticket", ticket))); 216 wireMock.register(WireMock.get(WireMock.urlPathMatching("/0.6/relations")).willReturn(WireMock.aResponse() 217 .withTransformer("MultiplePrimitiveTransformer", "ticket", ticket))); 218 wireMock.register(WireMock.get(WireMock.urlPathMatching("/0.6/ways")).willReturn(WireMock.aResponse() 219 .withTransformer("MultiplePrimitiveTransformer", "ticket", ticket))); 220 } 221 123 222 @Override 124 223 public String getName() { … … 151 250 152 251 private static String getReturnXml(int ticket, OsmPrimitiveType type, QueryParameter parameter) { 252 final Set<OsmParameterInformation> objectIds = (parameter.isSingleValued() 253 ? Arrays.asList(parameter.values().get(0).split(",", -1)) 254 : parameter.values()) 255 .stream().map(s -> new OsmParameterInformation(type, s)).collect(Collectors.toSet()); 256 return getReturnXml(ticket, type, objectIds); 257 } 258 259 private static String getReturnXml(int ticket, OsmPrimitiveType type, Collection<OsmParameterInformation> objectIds) { 153 260 final String file; 154 261 switch (type) { … … 165 272 throw new IllegalArgumentException("No file for type " + type); 166 273 } 167 final Set<OsmParameterInformation> objectIds = (parameter.isSingleValued()168 ? Arrays.asList(parameter.values().get(0).split(",", -1))169 : parameter.values()) 170 .stream().map(s -> new OsmParameterInformation(type, s)).collect(Collectors.toSet());274 return getObjectInformation(ticket, file, objectIds); 275 } 276 277 private static String getObjectInformation(int ticket, String file, Collection<OsmParameterInformation> objectIds) { 171 278 try (InputStream fis = Files.newInputStream(Paths.get(TestUtils.getRegressionDataDir(ticket), file)); 172 279 JsonReader reader = Json.createReader(fis)) { … … 185 292 Optional<OsmParameterInformation> info = objectIds.stream() 186 293 .filter(o -> !o.isVersioned() && o.type() == i.type() && o.id() == i.id()).findFirst(); 187 if (info.isPresent() && (matchingElements.get(info.get()) == null || matchingElements.get(info.get()).getInt("version") < i.version())) { 294 if (info.isPresent() && (matchingElements.get(info.get()) == null 295 || matchingElements.get(info.get()).getInt("version") < i.version())) { 188 296 Optional<OsmParameterInformation> previous = matchingElements.keySet().stream() 189 297 .filter(o -> o.type() == i.type() && o.id() == i.id()).findFirst(); … … 197 305 } 198 306 } 199 StringBuilder sb = new StringBuilder("<osm version=\"" + version + "\" generator=\"" + generator + "\" copyright=\"" + copyright + "\" attribution=\"" + attribution + "\" license=\"" + license + "\">"); 307 StringBuilder sb = new StringBuilder("<osm version=\"").append(version).append("\" generator=\"") 308 .append(generator).append("\" copyright=\"").append(copyright).append("\" attribution=\"") 309 .append(attribution).append("\" license=\"").append(license).append("\">"); 200 310 for (JsonObject element : matchingElements.values()) { 201 311 sb.append(elementToString(element)); … … 240 350 if (object.containsKey("tags")) { 241 351 for (Map.Entry<String, JsonValue> tag : object.getJsonObject("tags").entrySet()) { 242 sb.append("<tag k=\"").append(tag.getKey()).append("\" v=\"").append(((JsonString) tag.getValue()).getString().replace("\"", """)).append("\"/>"); 352 sb.append("<tag k=\"").append(tag.getKey()).append("\" v=\"") 353 .append(((JsonString) tag.getValue()).getString().replace("\"", """)) 354 .append("\"/>"); 243 355 } 244 356 } … … 261 373 } 262 374 } 375 } 376 377 /** 378 * A record class for parameter information. 379 */ 380 private static final class OsmParameterInformation { 381 private final OsmPrimitiveType type; 382 private final long id; 383 private final int version; 263 384 264 385 /** 265 * A record class for parameter information. 386 * Create a new record 387 * @param type The type 388 * @param param The URl parameter bit (can be something like {@code "123v1"}) 266 389 */ 267 private static final class OsmParameterInformation { 268 private final OsmPrimitiveType type; 269 private final long id; 270 private final int version; 271 272 /** 273 * Create a new record 274 * @param type The type 275 * @param param The URl parameter bit (can be something like {@code "123v1"}) 276 */ 277 public OsmParameterInformation(OsmPrimitiveType type, String param) { 278 this(type, Long.parseLong(param.split("v")[0]), 279 param.split("v").length == 2 ? Integer.parseInt(param.split("v")[1]) : Integer.MIN_VALUE); 280 } 281 282 /** 283 * Create a new record 284 * @param type The type 285 * @param id The primitive id 286 * @param version The primitive version. Anything less than or equal to 0 means latest.` 287 */ 288 public OsmParameterInformation(OsmPrimitiveType type, long id, int version) { 289 this.type = type; 290 this.id = id; 291 this.version = Math.max(version, 0); 292 } 293 294 public OsmPrimitiveType type() { 295 return this.type; 296 } 297 298 public long id() { 299 return this.id; 300 } 301 302 public int version() { 303 return this.version; 304 } 305 306 /** 307 * Check if this is versioned 308 * @return {@code true} if we are looking for a specific version instead of the latest. 309 */ 310 public boolean isVersioned() { 311 return this.version > 0; 312 } 313 314 @Override 315 public int hashCode() { 316 return Objects.hash(this.type, this.id, this.version); 317 } 318 319 @Override 320 public boolean equals(Object obj) { 321 if (obj instanceof OsmParameterInformation) { 322 OsmParameterInformation other = (OsmParameterInformation) obj; 323 return this.type == other.type && 324 this.id == other.id && 325 this.version == other.version; 326 } 327 return false; 328 } 329 330 @Override 331 public String toString() { 332 return "[type=\"" + this.type + "\" id=\"" + this.id + "\" version=\"" + this.version +"\"]"; 333 } 390 OsmParameterInformation(OsmPrimitiveType type, String param) { 391 this(type, Long.parseLong(param.split("v")[0]), 392 param.split("v").length == 2 ? Integer.parseInt(param.split("v")[1]) : Integer.MIN_VALUE); 393 } 394 395 /** 396 * Create a new record 397 * @param type The type 398 * @param id The primitive id 399 * @param version The primitive version. Anything less than or equal to 0 means latest.` 400 */ 401 OsmParameterInformation(OsmPrimitiveType type, long id, int version) { 402 this.type = type; 403 this.id = id; 404 this.version = Math.max(version, 0); 405 } 406 407 public OsmPrimitiveType type() { 408 return this.type; 409 } 410 411 public long id() { 412 return this.id; 413 } 414 415 public int version() { 416 return this.version; 417 } 418 419 /** 420 * Check if this is versioned 421 * @return {@code true} if we are looking for a specific version instead of the latest. 422 */ 423 public boolean isVersioned() { 424 return this.version > 0; 425 } 426 427 @Override 428 public int hashCode() { 429 return Objects.hash(this.type, this.id, this.version); 430 } 431 432 @Override 433 public boolean equals(Object obj) { 434 if (obj instanceof OsmParameterInformation) { 435 OsmParameterInformation other = (OsmParameterInformation) obj; 436 return this.type == other.type && 437 this.id == other.id && 438 this.version == other.version; 439 } 440 return false; 441 } 442 443 @Override 444 public String toString() { 445 return "[type=\"" + this.type + "\" id=\"" + this.id + "\" version=\"" + this.version +"\"]"; 334 446 } 335 447 }
Note:
See TracChangeset
for help on using the changeset viewer.