source: josm/trunk/test/unit/org/openstreetmap/josm/data/projection/ProjectionRegressionTest.java@ 7005

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

see #8465 - use diamond operator where applicable

  • Property svn:eol-style set to native
File size: 8.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.projection;
3
4import java.io.BufferedReader;
5import java.io.BufferedWriter;
6import java.io.File;
7import java.io.FileInputStream;
8import java.io.FileNotFoundException;
9import java.io.FileOutputStream;
10import java.io.IOException;
11import java.io.InputStreamReader;
12import java.io.OutputStreamWriter;
13import java.util.ArrayList;
14import java.util.Collection;
15import java.util.HashMap;
16import java.util.HashSet;
17import java.util.LinkedHashSet;
18import java.util.List;
19import java.util.Map;
20import java.util.Map.Entry;
21import java.util.Random;
22import java.util.Set;
23
24import org.junit.BeforeClass;
25import org.junit.Test;
26import org.openstreetmap.josm.Main;
27import org.openstreetmap.josm.data.Bounds;
28import org.openstreetmap.josm.data.coor.EastNorth;
29import org.openstreetmap.josm.data.coor.LatLon;
30import org.openstreetmap.josm.gui.preferences.projection.ProjectionChoice;
31import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
32import org.openstreetmap.josm.tools.Pair;
33import org.openstreetmap.josm.tools.Utils;
34
35/**
36 * This test is used to monitor changes in projection code.
37 *
38 * It keeps a record of test data in the file data_nodist/projection-regression-test-data.csv.
39 * This record is generated from the current Projection classes available in JOSM. It needs to
40 * be updated, whenever a projection is added / removed or an algorithm is changed, such that
41 * the computed values are numerically different. There is no error threshold, every change is reported.
42 *
43 * So when this test fails, first check if the change is intended. Then update the regression
44 * test data, by running the main method of this class and commit the new data file.
45 */
46public class ProjectionRegressionTest {
47
48 public static final String PROJECTION_DATA_FILE = "data_nodist/projection-regression-test-data.csv";
49
50 private static class TestData {
51 public String code;
52 public LatLon ll;
53 public EastNorth en;
54 public LatLon ll2;
55 }
56
57 public static void main(String[] args) throws IOException, FileNotFoundException {
58 setUp();
59
60 Map<String, Projection> supportedCodesMap = new HashMap<>();
61 for (ProjectionChoice pc : ProjectionPreference.getProjectionChoices()) {
62 for (String code : pc.allCodes()) {
63 Collection<String> pref = pc.getPreferencesFromCode(code);
64 pc.setPreferences(pref);
65 Projection p = pc.getProjection();
66 supportedCodesMap.put(code, p);
67 }
68 }
69
70 List<TestData> prevData = new ArrayList<>();
71 if (new File(PROJECTION_DATA_FILE).exists()) {
72 prevData = readData();
73 }
74 Map<String,TestData> prevCodesMap = new HashMap<>();
75 for (TestData data : prevData) {
76 prevCodesMap.put(data.code, data);
77 }
78
79 Set<String> codesToWrite = new LinkedHashSet<>();
80 for (TestData data : prevData) {
81 if (supportedCodesMap.containsKey(data.code)) {
82 codesToWrite.add(data.code);
83 }
84 }
85 for (String code : supportedCodesMap.keySet()) {
86 if (!codesToWrite.contains(code)) {
87 codesToWrite.add(code);
88 }
89 }
90
91 Random rand = new Random();
92 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(PROJECTION_DATA_FILE), Utils.UTF_8));
93 out.write("# Data for test/unit/org/openstreetmap/josm/data/projection/ProjectionRegressionTest.java\n");
94 out.write("# Format: 1. Projection code; 2. lat/lon; 3. lat/lon projected -> east/north; 4. east/north (3.) inverse projected\n");
95 for (Entry<String, Projection> e : supportedCodesMap.entrySet()) {
96 }
97 for (String code : codesToWrite) {
98 Projection proj = supportedCodesMap.get(code);
99 Bounds b = proj.getWorldBoundsLatLon();
100 double lat, lon;
101 TestData prev = prevCodesMap.get(proj.toCode());
102 if (prev != null) {
103 lat = prev.ll.lat();
104 lon = prev.ll.lon();
105 } else {
106 lat = b.getMin().lat() + rand.nextDouble() * (b.getMax().lat() - b.getMin().lat());
107 lon = b.getMin().lon() + rand.nextDouble() * (b.getMax().lon() - b.getMin().lon());
108 }
109 EastNorth en = proj.latlon2eastNorth(new LatLon(lat, lon));
110 LatLon ll2 = proj.eastNorth2latlon(en);
111 out.write(String.format("%s%n ll %s %s%n en %s %s%n ll2 %s %s%n", proj.toCode(), lat, lon, en.east(), en.north(), ll2.lat(), ll2.lon()));
112 }
113 out.close();
114 }
115
116 private static List<TestData> readData() throws IOException, FileNotFoundException {
117 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(PROJECTION_DATA_FILE), Utils.UTF_8));
118 List<TestData> result = new ArrayList<>();
119 String line;
120 while ((line = in.readLine()) != null) {
121 if (line.startsWith("#")) {
122 continue;
123 }
124 TestData next = new TestData();
125
126 Pair<Double,Double> ll = readLine("ll", in.readLine());
127 Pair<Double,Double> en = readLine("en", in.readLine());
128 Pair<Double,Double> ll2 = readLine("ll2", in.readLine());
129
130 next.code = line;
131 next.ll = new LatLon(ll.a, ll.b);
132 next.en = new EastNorth(en.a, en.b);
133 next.ll2 = new LatLon(ll2.a, ll2.b);
134
135 result.add(next);
136 }
137 in.close();
138 return result;
139 }
140
141 private static Pair<Double,Double> readLine(String expectedName, String input) {
142 String[] fields = input.trim().split("[ ]+");
143 if (fields.length != 3) throw new AssertionError();
144 if (!fields[0].equals(expectedName)) throw new AssertionError();
145 double a = Double.parseDouble(fields[1]);
146 double b = Double.parseDouble(fields[2]);
147 return Pair.create(a, b);
148 }
149
150 /**
151 * Setup test.
152 */
153 @BeforeClass
154 public static void setUp() {
155 Main.initApplicationPreferences();
156 }
157
158 @Test
159 public void regressionTest() throws IOException, FileNotFoundException {
160 List<TestData> allData = readData();
161 Set<String> dataCodes = new HashSet<>();
162 for (TestData data : allData) {
163 dataCodes.add(data.code);
164 }
165
166 StringBuilder fail = new StringBuilder();
167
168 for (ProjectionChoice pc : ProjectionPreference.getProjectionChoices()) {
169 for (String code : pc.allCodes()) {
170 if (!dataCodes.contains(code)) {
171 fail.append("Did not find projection "+code+" in test data!\n");
172 }
173 }
174 }
175
176 for (TestData data : allData) {
177 Projection proj = Projections.getProjectionByCode(data.code);
178 if (proj == null) {
179 fail.append("Projection "+data.code+" from test data was not found!\n");
180 continue;
181 }
182 EastNorth en = proj.latlon2eastNorth(data.ll);
183 if (!en.equals(data.en)) {
184 String error = String.format("%s (%s): Projecting latlon(%s,%s):%n" +
185 " expected: eastnorth(%s,%s),%n" +
186 " but got: eastnorth(%s,%s)!%n",
187 proj.toString(), data.code, data.ll.lat(), data.ll.lon(), data.en.east(), data.en.north(), en.east(), en.north());
188 fail.append(error);
189 }
190 LatLon ll2 = proj.eastNorth2latlon(data.en);
191 if (!ll2.equals(data.ll2)) {
192 String error = String.format("%s (%s): Inverse projecting eastnorth(%s,%s):%n" +
193 " expected: latlon(%s,%s),%n" +
194 " but got: latlon(%s,%s)!%n",
195 proj.toString(), data.code, data.en.east(), data.en.north(), data.ll2.lat(), data.ll2.lon(), ll2.lat(), ll2.lon());
196 fail.append(error);
197 }
198 }
199
200 if (fail.length() > 0) {
201 System.err.println(fail.toString());
202 throw new AssertionError(fail.toString());
203 }
204 }
205}
Note: See TracBrowser for help on using the repository browser.