1 /* test for gpsdclient.c: function deg_to_str
2 *
3 * Consider rounding off also:
4 * dsec = (int)(fdsec * 10000.0 + 0.5);
5 *
6 * This file is Copyright (c) 2010 by the GPSD project
7 * SPDX-License-Identifier: BSD-2-clause
8 */
9
10 /* first so the #defs work */
11 #include "../gpsd_config.h"
12 #include <math.h> /* for nan() */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h> /* for getopt() */
17 #include "../gpsdclient.h"
18 #include "../revision.h"
19
20 struct test {
21 double deg;
22 char dd[20];
23 char dd2[20];
24 char ddmm[20];
25 char ddmm2[20];
26 char ddmmss[20];
27 char ddmmss2[20];
28 };
29
30 #define NANFLAG 9999
31
32 struct test tests[] = {
33 /* 1.999999995 sec */
34 {(1.999999995),
35 " 2.00000000", /* rounded up */
36 " 2.00000000 E", /* rounded up */
37 " 2 00.000000'", /* rounded up */
38 " 2 00.000000' E", /* rounded up */
39 " 1 59' 59.99998\"",
40 " 1 59' 59.99998\" N"},
41 /* 3.999999999 sec */
42 {(3.999999994),
43 " 3.99999999", /* not rounded up */
44 " 3.99999999 E", /* not rounded up */
45 " 4 00.000000'", /* rounded up */
46 " 4 00.000000' E", /* rounded up */
47 " 3 59' 59.99998\"",
48 " 3 59' 59.99998\" N"},
49 /* 5 degree, 1.99999960 arcmin */
50 {(5.0 + 1.999999600/60.0),
51 " 5.03333333",
52 " 5.03333333 E",
53 " 5 02.000000'", /* rounded up */
54 " 5 02.000000' E", /* rounded up */
55 " 5 01' 59.99998\"",
56 " 5 01' 59.99998\" N"},
57 /* 6 degree, 1.99999940 arcmin */
58 {(6.0 + 1.999999400/60.0),
59 " 6.03333332",
60 " 6.03333332 E",
61 " 6 01.999999'", /* not rounded up */
62 " 6 01.999999' E", /* not rounded up */
63 " 6 01' 59.99996\"",
64 " 6 01' 59.99996\" N"},
65 /* 7 degree, 59.99999960 arcmin */
66 {(7.0 + 59.999999600/60.0),
67 " 7.99999999",
68 " 7.99999999 E",
69 " 8 00.000000'", /* rounded up */
70 " 8 00.000000' E", /* rounded up */
71 " 7 59' 59.99998\"",
72 " 7 59' 59.99998\" N"},
73 /* 9 degree, 59.99999940 arcmin */
74 {(9.0 + 59.999999400/60.0),
75 " 9.99999999",
76 " 9.99999999 E",
77 " 9 59.999999'", /* not rounded up */
78 " 9 59.999999' E", /* not rounded up */
79 " 9 59' 59.99996\"",
80 " 9 59' 59.99996\" N"},
81 /* 11 degree, 1 arcminute, 1.99999600 arcsec */
82 {(11.0 + 1.0/60.0 + 1.99999600/3600.0),
83 " 11.01722222",
84 " 11.01722222 E",
85 " 11 01.033333'",
86 " 11 01.033333' E",
87 " 11 01' 02.00000\"", /* rounded up */
88 " 11 01' 02.00000\" N"}, /* rounded up */
89 /* 12 deg, 2 min, 2.99999400 sec */
90 {(12.0 + 2.0/60.0 + 2.99999400/3600.0),
91 " 12.03416667",
92 " 12.03416667 E",
93 " 12 02.050000'",
94 " 12 02.050000' E",
95 " 12 02' 02.99999\"", /* not rounded up */
96 " 12 02' 02.99999\" N"}, /* not rounded up */
97 /* 13.00000001 sec, LSB of dd */
98 {-13.00000001,
99 " 13.00000001",
100 " 13.00000001 W",
101 " 13 00.000001'",
102 " 13 00.000001' W",
103 " 13 00' 00.00004\"",
104 " 13 00' 00.00004\" S"},
105 /* 14 deg, 0.000001 min, LSB of ddmm */
106 {(14.0 + 0.000001/60.0),
107 " 14.00000002",
108 " 14.00000002 E",
109 " 14 00.000001'",
110 " 14 00.000001' E",
111 " 14 00' 00.00006\"",
112 " 14 00' 00.00006\" N"},
113 /* 15 deg, 2 min, 2.00001 sec, LSB of ddmmss */
114 {(15.0 + 2.0/60.0 + 2.00001/3600.0),
115 " 15.03388889",
116 " 15.03388889 E",
117 " 15 02.033334'",
118 " 15 02.033334' E",
119 " 15 02' 02.00001\"",
120 " 15 02' 02.00001\" N"},
121 /* -44.99999999999 */
122 /* fabs() */
123 {-44.0,
124 " 44.00000000",
125 " 44.00000000 W",
126 " 44 00.000000'",
127 " 44 00.000000' W",
128 " 44 00' 00.00000\"",
129 " 44 00' 00.00000\" S"},
130 /* 359.99999999999 */
131 {359.99999999999,
132 " 0.00000000", /* rounded up, and rolled over */
133 " 0.00000000 E", /* rounded up, and rolled over */
134 " 0 00.000000'",
135 " 0 00.000000' E",
136 " 0 00' 00.00000\"",
137 " 0 00' 00.00000\" N"},
138 /* 361 */
139 /* nan because out of range */
140 {361,
141 "n/a",
142 "n/a",
143 "n/a",
144 "n/a",
145 "n/a",
146 "n/a"},
147 /* -361 */
148 /* nan, just because */
149 {NANFLAG,
150 "n/a",
151 "n/a",
152 "n/a",
153 "n/a",
154 "n/a",
155 "n/a"},
156 /* FP_INFINITE */
157 /* gcc too 'smart' to let us put a Nan here */
158 {9999,
159 "n/a",
160 "n/a",
161 "n/a",
162 "n/a",
163 "n/a",
164 "n/a"},
165 };
166
167
168 struct test2 {
169 double lat;
170 double lon;
171 char *maidenhead;
172 char *name;
173 };
174
175 struct test2 tests2[] = {
176 /* maidenhead
177 * keep in sync with test_clienthelpers.py */
178 {48.86471, 2.37305, "JN18eu", "Paris"},
179 {41.93498, 12.43652, "JN61fw", "Rome"},
180 {39.9771, -75.1685, "FM29jx", "Philadelphia"},
181 {-23.4028, -50.9766, "GG46mo", "Sao Paulo"},
182 {90, 180, "RR99xx", "North Pole"},
183 {-90, -180, "AA00aa", "South Pole"},
184 };
185
186
main(int argc,char ** argv)187 int main(int argc, char **argv)
188 {
189 char buf[20];
190 char *s;
191 unsigned int i;
192 int verbose = 0;
193 int fail_count = 0;
194 int option;
195
196 while ((option = getopt(argc, argv, "h?vV")) != -1) {
197 switch (option) {
198 default:
199 fail_count = 1;
200 /* FALLTHROUGH */
201 case '?':
202 /* FALLTHROUGH */
203 case 'h':
204 (void)fputs("usage: test_gpsdclient [-v] [-V]\n", stderr);
205 exit(fail_count);
206 case 'V':
207 (void)fprintf( stderr, "test_gpsdclient %s\n",
208 VERSION);
209 exit(EXIT_SUCCESS);
210 case 'v':
211 verbose = 1;
212 break;
213 }
214 }
215
216
217 for (i = 0; i < (sizeof(tests)/sizeof(struct test)); i++) {
218 if (NANFLAG == tests[i].deg) {
219 /* make it a NaN */
220 tests[i].deg = nan("a");
221 }
222 s = deg_to_str(deg_dd, tests[i].deg);
223 if (0 != strcmp(s, tests[i].dd)) {
224 printf("ERROR: %s s/b %s\n", s, tests[i].dd);
225 fail_count++;
226 } else if (0 < verbose) {
227 printf("%s s/b %s\n", s, tests[i].dd);
228 }
229 s = deg_to_str2(deg_dd, tests[i].deg, buf,
230 sizeof(buf), " E", " W");
231 if (0 != strcmp(s, tests[i].dd2)) {
232 printf("ERROR: %s s/b %s\n", s, tests[i].dd2);
233 fail_count++;
234 } else if (0 < verbose) {
235 printf("%s s/b %s\n", s, tests[i].dd2);
236 }
237 s = deg_to_str(deg_ddmm, tests[i].deg);
238 if (0 != strcmp(s, tests[i].ddmm)) {
239 printf("ERROR: %s s/b %s\n", s, tests[i].ddmm);
240 fail_count++;
241 } else if (0 < verbose) {
242 printf("%s s/b %s\n", s, tests[i].ddmm);
243 }
244 s = deg_to_str2(deg_ddmm, tests[i].deg, buf,
245 sizeof(buf), " E", " W");
246 if (0 != strcmp(s, tests[i].ddmm2)) {
247 printf("ERROR: %s s/b %s\n", s, tests[i].ddmm2);
248 fail_count++;
249 } else if (0 < verbose) {
250 printf("%s s/b %s\n", s, tests[i].ddmm2);
251 }
252 s = deg_to_str(deg_ddmmss, tests[i].deg);
253 if (0 != strcmp(s, tests[i].ddmmss)) {
254 printf("ERROR: %s s/b %s\n", s, tests[i].ddmmss);
255 fail_count++;
256 } else if (0 < verbose) {
257 printf("%s s/b %s\n", s, tests[i].ddmmss);
258 }
259 s = deg_to_str2(deg_ddmmss, tests[i].deg, buf,
260 sizeof(buf), " N", " S");
261 if (0 != strcmp(s, tests[i].ddmmss2)) {
262 printf("ERROR: %s s/b %s\n", s, tests[i].ddmmss2);
263 fail_count++;
264 } else if (0 < verbose) {
265 printf("%s s/b %s\n", s, tests[i].ddmmss2);
266 }
267 }
268
269 for (i = 0; i < (sizeof(tests2)/sizeof(struct test2)); i++) {
270 s = maidenhead(tests2[i].lat, tests2[i].lon);
271 if (0 != strcmp(s, tests2[i].maidenhead)) {
272 printf("ERROR: %s s/b %s\n", s, tests2[i].maidenhead);
273 fail_count++;
274 } else if (0 < verbose) {
275 printf("%s s/b %s\n", s, tests2[i].maidenhead);
276 }
277 }
278
279 exit(fail_count);
280 }
281
282