source: josm/trunk/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java@ 18287

Last change on this file since 18287 was 18287, checked in by Don-vip, 3 years ago

fix #20913 - fix handling of GPX files in sessions (patch by Bjoeni)

  • revert r17659 (except for unit tests) - see #20233
    • don't save GPX track and marker colors in session file anymore, but in the GPX files as extensions (like before)
    • don't ask to save unmodified GPX file
    • don't override global color settings when individual track doesn't have a color
  • ask user to save changes to GPX file when any drawing settings or marker colors have changed (currently only happens for track colors)
  • save marker color values to session even when corresponding GPX layer has already been deleted
  • save alpha values for GPX marker colors
  • added explanation to the "overwrite GPX file" dialog
  • inform user if not all files referenced by the session file are saved yet
  • allow user to save all files that are not included in the *.jos/*.joz but are only referenced in the session file
  • display * next to GPX layers that need to be saved (move isDirty() logic from OsmDataLayer to AbstractModifiableLayer)
  • Property svn:eol-style set to native
File size: 10.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.session;
3
4import static org.junit.jupiter.api.Assertions.assertEquals;
5import static org.junit.jupiter.api.Assertions.fail;
6
7import java.awt.Color;
8import java.io.File;
9import java.io.IOException;
10import java.nio.charset.StandardCharsets;
11import java.nio.file.Files;
12import java.nio.file.Path;
13import java.nio.file.Paths;
14import java.time.Instant;
15import java.util.Arrays;
16import java.util.Collections;
17import java.util.HashMap;
18import java.util.List;
19import java.util.Map;
20import java.util.stream.Collectors;
21import java.util.zip.ZipEntry;
22import java.util.zip.ZipFile;
23
24import org.junit.jupiter.api.BeforeEach;
25import org.junit.jupiter.api.Test;
26import org.junit.jupiter.api.extension.RegisterExtension;
27import org.openstreetmap.josm.TestUtils;
28import org.openstreetmap.josm.data.coor.LatLon;
29import org.openstreetmap.josm.data.gpx.GpxData;
30import org.openstreetmap.josm.data.gpx.WayPoint;
31import org.openstreetmap.josm.data.imagery.ImageryInfo;
32import org.openstreetmap.josm.data.imagery.OffsetBookmark;
33import org.openstreetmap.josm.data.notes.Note;
34import org.openstreetmap.josm.data.osm.DataSet;
35import org.openstreetmap.josm.data.projection.ProjectionRegistry;
36import org.openstreetmap.josm.gui.MainApplication;
37import org.openstreetmap.josm.gui.layer.GpxLayer;
38import org.openstreetmap.josm.gui.layer.ImageryLayer;
39import org.openstreetmap.josm.gui.layer.Layer;
40import org.openstreetmap.josm.gui.layer.NoteLayer;
41import org.openstreetmap.josm.gui.layer.OsmDataLayer;
42import org.openstreetmap.josm.gui.layer.TMSLayer;
43import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
44import org.openstreetmap.josm.testutils.JOSMTestRules;
45import org.openstreetmap.josm.tools.MultiMap;
46import org.openstreetmap.josm.tools.Utils;
47
48import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
49
50/**
51 * Unit tests for Session writing.
52 */
53class SessionWriterTest {
54
55 protected static final class OsmHeadlessJosExporter extends OsmDataSessionExporter {
56 public OsmHeadlessJosExporter(OsmDataLayer layer) {
57 super(layer);
58 }
59
60 @Override
61 public boolean requiresZip() {
62 return false;
63 }
64 }
65
66 protected static final class OsmHeadlessJozExporter extends OsmDataSessionExporter {
67 public OsmHeadlessJozExporter(OsmDataLayer layer) {
68 super(layer);
69 }
70
71 @Override
72 public boolean requiresZip() {
73 return true;
74 }
75 }
76
77 protected static final class GpxHeadlessJosExporter extends GpxTracksSessionExporter {
78 public GpxHeadlessJosExporter(GpxLayer layer) {
79 super(layer);
80 }
81
82 @Override
83 public boolean requiresZip() {
84 return false;
85 }
86 }
87
88 protected static final class GpxHeadlessJozExporter extends GpxTracksSessionExporter {
89 public GpxHeadlessJozExporter(GpxLayer layer) {
90 super(layer);
91 }
92
93 @Override
94 public boolean requiresZip() {
95 return true;
96 }
97 }
98
99 /**
100 * Setup tests.
101 */
102 @RegisterExtension
103 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
104 public JOSMTestRules test = new JOSMTestRules().projection().main();
105
106 /**
107 * Setup tests.
108 */
109 @BeforeEach
110 public void setUp() {
111 MainApplication.getLayerManager().addLayer(createOsmLayer());
112 }
113
114 private Map<String, byte[]> testWrite(List<Layer> layers, final boolean zip) throws IOException {
115 Map<Layer, SessionLayerExporter> exporters = new HashMap<>();
116 if (zip) {
117 SessionWriter.registerSessionLayerExporter(OsmDataLayer.class, OsmHeadlessJozExporter.class);
118 SessionWriter.registerSessionLayerExporter(GpxLayer.class, GpxHeadlessJozExporter.class);
119 } else {
120 SessionWriter.registerSessionLayerExporter(OsmDataLayer.class, OsmHeadlessJosExporter.class);
121 SessionWriter.registerSessionLayerExporter(GpxLayer.class, GpxHeadlessJosExporter.class);
122 }
123 for (final Layer l : layers) {
124 SessionLayerExporter s = SessionWriter.getSessionLayerExporter(l);
125 exporters.put(l, s);
126 if (s instanceof GpxTracksSessionExporter) {
127 ((GpxTracksSessionExporter) s).setMetaTime(Instant.parse("2021-10-16T18:27:12.351Z"));
128 } else if (s instanceof MarkerSessionExporter) {
129 ((MarkerSessionExporter) s).setMetaTime(Instant.parse("2021-10-16T18:27:12.351Z"));
130 }
131 }
132 SessionWriter sw = new SessionWriter(layers, -1, exporters, new MultiMap<Layer, Layer>(), zip);
133 File file = new File(System.getProperty("java.io.tmpdir"), getClass().getName()+(zip ? ".joz" : ".jos"));
134 try {
135 sw.write(file);
136 if (!zip) {
137 return null;
138 }
139 try (ZipFile zipFile = new ZipFile(file)) {
140 return Collections.list(zipFile.entries()).stream().collect(Collectors.toMap(ZipEntry::getName, e -> {
141 try {
142 return Utils.readBytesFromStream(zipFile.getInputStream(e));
143 } catch (IOException ex) {
144 fail(ex);
145 }
146 return null;
147 }));
148 }
149 } finally {
150 if (file.exists()) {
151 Utils.deleteFile(file);
152 }
153 }
154 }
155
156 private OsmDataLayer createOsmLayer() {
157 OsmDataLayer layer = new OsmDataLayer(new DataSet(), "OSM layer name", null);
158 layer.setAssociatedFile(new File("data.osm"));
159 return layer;
160 }
161
162 private GpxLayer createGpxLayer() {
163 GpxData data = new GpxData();
164 WayPoint wp = new WayPoint(new LatLon(42.72665, -0.00747));
165 wp.setInstant(Instant.parse("2021-01-01T10:15:30.00Z"));
166 data.waypoints.add(wp);
167 data.waypoints.add(new WayPoint(new LatLon(42.72659, -0.00749)));
168 GpxLayer layer = new GpxLayer(data, "GPX layer name");
169 layer.setAssociatedFile(new File("data.gpx"));
170 return layer;
171 }
172
173 private MarkerLayer createMarkerLayer(GpxLayer gpx) {
174 MarkerLayer layer = new MarkerLayer(gpx.data, "Marker layer name", gpx.getAssociatedFile(), gpx);
175 layer.setOpacity(0.5);
176 layer.setColor(new Color(0x12345678, true));
177 return layer;
178 }
179
180 private ImageryLayer createImageryLayer() {
181 TMSLayer layer = new TMSLayer(new ImageryInfo("the name", "http://www.url.com/"));
182 layer.getDisplaySettings().setOffsetBookmark(
183 new OffsetBookmark(ProjectionRegistry.getProjection().toCode(), layer.getInfo().getId(), layer.getInfo().getName(), "", 12, 34));
184 return layer;
185 }
186
187 private NoteLayer createNoteLayer() {
188 return new NoteLayer(Arrays.asList(new Note(LatLon.ZERO)), "layer name");
189 }
190
191 /**
192 * Tests to write an empty .jos file.
193 * @throws IOException if an I/O error occurs
194 */
195 @Test
196 void testWriteEmptyJos() throws IOException {
197 testWrite(Collections.<Layer>emptyList(), false);
198 }
199
200 /**
201 * Tests to write an empty .joz file.
202 * @throws IOException if an I/O error occurs
203 */
204 @Test
205 void testWriteEmptyJoz() throws IOException {
206 testWrite(Collections.<Layer>emptyList(), true);
207 }
208
209 /**
210 * Tests to write a .jos file containing OSM data.
211 * @throws IOException if an I/O error occurs
212 */
213 @Test
214 void testWriteOsmJos() throws IOException {
215 testWrite(Collections.<Layer>singletonList(createOsmLayer()), false);
216 }
217
218 /**
219 * Tests to write a .joz file containing OSM data.
220 * @throws IOException if an I/O error occurs
221 */
222 @Test
223 void testWriteOsmJoz() throws IOException {
224 testWrite(Collections.<Layer>singletonList(createOsmLayer()), true);
225 }
226
227 /**
228 * Tests to write a .jos file containing GPX data.
229 * @throws IOException if an I/O error occurs
230 */
231 @Test
232 void testWriteGpxJos() throws IOException {
233 testWrite(Collections.<Layer>singletonList(createGpxLayer()), false);
234 }
235
236 /**
237 * Tests to write a .joz file containing GPX data.
238 * @throws IOException if an I/O error occurs
239 */
240 @Test
241 void testWriteGpxJoz() throws IOException {
242 testWrite(Collections.<Layer>singletonList(createGpxLayer()), true);
243 }
244
245 /**
246 * Tests to write a .joz file containing GPX and marker data.
247 * @throws IOException if an I/O error occurs
248 */
249 @Test
250 void testWriteGpxAndMarkerJoz() throws IOException {
251 GpxLayer gpx = createGpxLayer();
252 Map<String, byte[]> bytes = testWrite(Arrays.asList(gpx, createMarkerLayer(gpx)), true);
253
254 Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers.jos");
255 String expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
256 String actual = new String(bytes.get("session.jos"), StandardCharsets.UTF_8).replace("\r", "");
257 assertEquals(expected, actual);
258
259 path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/data_export.gpx");
260 expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
261 actual = new String(bytes.get("layers/01/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
262 assertEquals(expected, actual);
263
264 path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/markers.gpx");
265 expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
266 actual = new String(bytes.get("layers/02/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
267 assertEquals(expected, actual);
268 }
269
270 /**
271 * Tests to write a .joz file containing an imagery layer.
272 * @throws IOException if an I/O error occurs
273 */
274 @Test
275 void testWriteImageryLayer() throws IOException {
276 final Layer layer = createImageryLayer();
277 testWrite(Collections.singletonList(layer), true);
278 }
279
280 /**
281 * Tests to write a .joz file containing a note layer.
282 * @throws IOException if an I/O error occurs
283 */
284 @Test
285 void testWriteNoteLayer() throws IOException {
286 final Layer layer = createNoteLayer();
287 testWrite(Collections.singletonList(layer), true);
288 }
289}
Note: See TracBrowser for help on using the repository browser.