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