test_gpsdclient.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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 2010 by the GPSD project
  7. * SPDX-License-Identifier: BSD-2-clause
  8. */
  9. #include "../include/gpsd_config.h" // first so the #ifdefs work
  10. #include <math.h> // for nan()
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <unistd.h> // for getopt()
  15. #include "../include/compiler.h" // for FALLTHROUGH
  16. #include "../include/gpsdclient.h"
  17. #include "../include/os_compat.h"
  18. struct test {
  19. double deg;
  20. char dd[20];
  21. char dd2[20];
  22. char ddmm[20];
  23. char ddmm2[20];
  24. char ddmmss[20];
  25. char ddmmss2[20];
  26. };
  27. #define NANFLAG 9999
  28. struct test tests[] = {
  29. // 1.999999995 sec
  30. {(1.999999995),
  31. " 2.00000000", // rounded up
  32. " 2.00000000 E", // rounded up
  33. " 2 00.000000'", // rounded up
  34. " 2 00.000000' E", // rounded up
  35. " 1 59' 59.99998\"",
  36. " 1 59' 59.99998\" N"},
  37. // 3.999999999 sec
  38. {(3.999999994),
  39. " 3.99999999", // not rounded up
  40. " 3.99999999 E", // not rounded up
  41. " 4 00.000000'", // rounded up
  42. " 4 00.000000' E", // rounded up
  43. " 3 59' 59.99998\"",
  44. " 3 59' 59.99998\" N"},
  45. // 5 degree, 1.99999960 arcmin
  46. {(5.0 + 1.999999600/60.0),
  47. " 5.03333333",
  48. " 5.03333333 E",
  49. " 5 02.000000'", // rounded up
  50. " 5 02.000000' E", // rounded up
  51. " 5 01' 59.99998\"",
  52. " 5 01' 59.99998\" N"},
  53. // 6 degree, 1.99999940 arcmin
  54. {(6.0 + 1.999999400/60.0),
  55. " 6.03333332",
  56. " 6.03333332 E",
  57. " 6 01.999999'", // not rounded up
  58. " 6 01.999999' E", // not rounded up
  59. " 6 01' 59.99996\"",
  60. " 6 01' 59.99996\" N"},
  61. // 7 degree, 59.99999960 arcmin
  62. {(7.0 + 59.999999600/60.0),
  63. " 7.99999999",
  64. " 7.99999999 E",
  65. " 8 00.000000'", // rounded up
  66. " 8 00.000000' E", // rounded up
  67. " 7 59' 59.99998\"",
  68. " 7 59' 59.99998\" N"},
  69. // 9 degree, 59.99999940 arcmin
  70. {(9.0 + 59.999999400/60.0),
  71. " 9.99999999",
  72. " 9.99999999 E",
  73. " 9 59.999999'", // not rounded up
  74. " 9 59.999999' E", // not rounded up
  75. " 9 59' 59.99996\"",
  76. " 9 59' 59.99996\" N"},
  77. // 11 degree, 1 arcminute, 1.99999600 arcsec
  78. {(11.0 + 1.0/60.0 + 1.99999600/3600.0),
  79. " 11.01722222",
  80. " 11.01722222 E",
  81. " 11 01.033333'",
  82. " 11 01.033333' E",
  83. " 11 01' 02.00000\"", // rounded up
  84. " 11 01' 02.00000\" N"}, // rounded up
  85. // 12 deg, 2 min, 2.99999400 sec
  86. {(12.0 + 2.0/60.0 + 2.99999400/3600.0),
  87. " 12.03416667",
  88. " 12.03416667 E",
  89. " 12 02.050000'",
  90. " 12 02.050000' E",
  91. " 12 02' 02.99999\"", // not rounded up
  92. " 12 02' 02.99999\" N"}, // not rounded up
  93. // 13.00000001 sec, LSB of dd
  94. {-13.00000001,
  95. " 13.00000001",
  96. " 13.00000001 W",
  97. " 13 00.000001'",
  98. " 13 00.000001' W",
  99. " 13 00' 00.00004\"",
  100. " 13 00' 00.00004\" S"},
  101. // 14 deg, 0.000001 min, LSB of ddmm
  102. {(14.0 + 0.000001/60.0),
  103. " 14.00000002",
  104. " 14.00000002 E",
  105. " 14 00.000001'",
  106. " 14 00.000001' E",
  107. " 14 00' 00.00006\"",
  108. " 14 00' 00.00006\" N"},
  109. // 15 deg, 2 min, 2.00001 sec, LSB of ddmmss
  110. {(15.0 + 2.0/60.0 + 2.00001/3600.0),
  111. " 15.03388889",
  112. " 15.03388889 E",
  113. " 15 02.033334'",
  114. " 15 02.033334' E",
  115. " 15 02' 02.00001\"",
  116. " 15 02' 02.00001\" N"},
  117. // -44.99999999999
  118. // fabs()
  119. {-44.0,
  120. " 44.00000000",
  121. " 44.00000000 W",
  122. " 44 00.000000'",
  123. " 44 00.000000' W",
  124. " 44 00' 00.00000\"",
  125. " 44 00' 00.00000\" S"},
  126. // 359.99999999999
  127. {359.99999999999,
  128. " 0.00000000", // rounded up, and rolled over
  129. " 0.00000000 E", // rounded up, and rolled over
  130. " 0 00.000000'",
  131. " 0 00.000000' E",
  132. " 0 00' 00.00000\"",
  133. " 0 00' 00.00000\" N"},
  134. // 361
  135. // nan because out of range
  136. {361,
  137. "n/a",
  138. "n/a",
  139. "n/a",
  140. "n/a",
  141. "n/a",
  142. "n/a"},
  143. // -361
  144. // nan, just because
  145. {NANFLAG,
  146. "n/a",
  147. "n/a",
  148. "n/a",
  149. "n/a",
  150. "n/a",
  151. "n/a"},
  152. // FP_INFINITE
  153. // gcc too 'smart' to let us put a Nan here
  154. {9999,
  155. "n/a",
  156. "n/a",
  157. "n/a",
  158. "n/a",
  159. "n/a",
  160. "n/a"},
  161. };
  162. struct test2 {
  163. double lat;
  164. double lon;
  165. char *maidenhead;
  166. char *name;
  167. };
  168. struct test2 tests2[] = {
  169. /* maidenhead
  170. * keep in sync with test_clienthelpers.py */
  171. {48.86471, 2.37305, "JN18eu47", "Paris"},
  172. {41.93498, 12.43652, "JN61fw24", "Rome"},
  173. {39.9771, -75.1685, "FM29jx94", "Philadelphia, PA USA"},
  174. {44.06878, -121.31424, "CN94ib26", "Bend, OR USA"},
  175. {-23.4028, -50.9766, "GG46mo23", "Sao Paulo"},
  176. {-33.86881, 151.20929 , "QF56od51", "Sydney, NSW AU"},
  177. {90, 180, "RR99xx99", "North Pole"},
  178. {-90, -180, "AA00aa00", "South Pole"},
  179. {91, 0, " n/a ", "Invalid Latitude"},
  180. {-91, 0, " n/a ", "Invalid Latitude"},
  181. {0, 200, " n/a ", "Invalid Longitude"},
  182. {0, 1200, " n/a ", "Invalid Longitude"},
  183. };
  184. struct fixsource_t tests3[] = {
  185. {"", "", "2947", NULL},
  186. {":", "localhost", "2947", NULL},
  187. {"::", "localhost", "2947", NULL},
  188. {"::/dev/111", "localhost", "2947", "/dev/111"},
  189. {":1111", "localhost", "1111", NULL},
  190. {":1111:", "localhost", "1111", NULL},
  191. {":1111:/dev/111", "localhost", "1111", "/dev/111"},
  192. {"example.com", "example.com", "2947", NULL},
  193. {"example.com:", "example.com", "2947", NULL},
  194. {"example.com::", "example.com", "2947", NULL},
  195. {"example.com:1111", "example.com", "1111", NULL},
  196. {"example.com:1111:", "example.com", "1111", NULL},
  197. {"example.com:1111:/dev/111", "example.com", "1111", "/dev/111"},
  198. // IPv6 literals
  199. {"[fe80:1:1::1]", "fe80:1:1::1", "2947", NULL},
  200. {"[fe80:1:1::1]:1111", "fe80:1:1::1", "1111", NULL},
  201. {"[fe80:1:1::1]:1111:", "fe80:1:1::1", "1111", NULL},
  202. {"[fe80:1:1::1]:1111:/dev/111", "fe80:1:1::1", "1111", "/dev/111"},
  203. };
  204. // Compare strings, allowing for NULL
  205. static int strcmp_null(char *s1, char *s2)
  206. {
  207. if (NULL == s1) {
  208. if (NULL == s2) {
  209. return 0;
  210. }
  211. return 1;
  212. }
  213. if (NULL == s2) {
  214. return -1;
  215. }
  216. return strcmp(s1, s2);
  217. }
  218. int main(int argc, char **argv)
  219. {
  220. char buf[20];
  221. const char *s;
  222. unsigned int i;
  223. int verbose = 0;
  224. int fail_count = 0;
  225. int option;
  226. struct fixsource_t source;
  227. while ((option = getopt(argc, argv, "h?vV")) != -1) {
  228. switch (option) {
  229. default:
  230. fail_count = 1;
  231. FALLTHROUGH
  232. case '?':
  233. FALLTHROUGH
  234. case 'h':
  235. (void)fputs("usage: test_gpsdclient [-v] [-V]\n", stderr);
  236. exit(fail_count);
  237. case 'V':
  238. (void)fprintf( stderr, "test_gpsdclient %s\n",
  239. VERSION);
  240. exit(EXIT_SUCCESS);
  241. case 'v':
  242. verbose = 1;
  243. break;
  244. }
  245. }
  246. for (i = 0; i < (sizeof(tests) / sizeof(struct test)); i++) {
  247. if (NANFLAG == tests[i].deg) {
  248. // make it a NaN
  249. tests[i].deg = nan("a");
  250. }
  251. s = deg_to_str(deg_dd, tests[i].deg);
  252. if (0 != strcmp(s, tests[i].dd)) {
  253. printf("ERROR: %s s/b %s\n", s, tests[i].dd);
  254. fail_count++;
  255. } else if (0 < verbose) {
  256. printf("%s s/b %s\n", s, tests[i].dd);
  257. }
  258. s = deg_to_str2(deg_dd, tests[i].deg, buf,
  259. sizeof(buf), " E", " W");
  260. if (0 != strcmp(s, tests[i].dd2)) {
  261. printf("ERROR: %s s/b %s\n", s, tests[i].dd2);
  262. fail_count++;
  263. } else if (0 < verbose) {
  264. printf("%s s/b %s\n", s, tests[i].dd2);
  265. }
  266. s = deg_to_str(deg_ddmm, tests[i].deg);
  267. if (0 != strcmp(s, tests[i].ddmm)) {
  268. printf("ERROR: %s s/b %s\n", s, tests[i].ddmm);
  269. fail_count++;
  270. } else if (0 < verbose) {
  271. printf("%s s/b %s\n", s, tests[i].ddmm);
  272. }
  273. s = deg_to_str2(deg_ddmm, tests[i].deg, buf,
  274. sizeof(buf), " E", " W");
  275. if (0 != strcmp(s, tests[i].ddmm2)) {
  276. printf("ERROR: %s s/b %s\n", s, tests[i].ddmm2);
  277. fail_count++;
  278. } else if (0 < verbose) {
  279. printf("%s s/b %s\n", s, tests[i].ddmm2);
  280. }
  281. s = deg_to_str(deg_ddmmss, tests[i].deg);
  282. if (0 != strcmp(s, tests[i].ddmmss)) {
  283. printf("ERROR: %s s/b %s\n", s, tests[i].ddmmss);
  284. fail_count++;
  285. } else if (0 < verbose) {
  286. printf("%s s/b %s\n", s, tests[i].ddmmss);
  287. }
  288. s = deg_to_str2(deg_ddmmss, tests[i].deg, buf,
  289. sizeof(buf), " N", " S");
  290. if (0 != strcmp(s, tests[i].ddmmss2)) {
  291. printf("ERROR: %s s/b %s\n", s, tests[i].ddmmss2);
  292. fail_count++;
  293. } else if (0 < verbose) {
  294. printf("%s s/b %s\n", s, tests[i].ddmmss2);
  295. }
  296. }
  297. for (i = 0; i < (sizeof(tests2) / sizeof(struct test2)); i++) {
  298. s = maidenhead(tests2[i].lat, tests2[i].lon);
  299. if (0 != strcmp(s, tests2[i].maidenhead)) {
  300. printf("ERROR: %s s/b %s\n", s, tests2[i].maidenhead);
  301. fail_count++;
  302. } else if (0 < verbose) {
  303. printf("%s s/b %s\n", s, tests2[i].maidenhead);
  304. }
  305. }
  306. for (i = 0; i < (sizeof(tests3) / sizeof(struct fixsource_t)); i++) {
  307. char spec[200];
  308. // no leftovers wanted
  309. memset(&source, 0, sizeof(source));
  310. // test.spec has to be r/w
  311. strlcpy(spec, tests3[i].spec, sizeof(spec));
  312. // gpsd_source_spec() eats spec
  313. gpsd_source_spec(spec, &source);
  314. if (0 != strcmp_null(source.server, tests3[i].server) ||
  315. 0 != strcmp_null(source.port, tests3[i].port) ||
  316. 0 != strcmp_null(source.device, tests3[i].device)) {
  317. printf("ERROR: spec: '%s' '%s' '%s' '%s' s/b '%s' '%s' '%s'\n",
  318. tests3[i].spec, source.server, source.port, source.device,
  319. tests3[i].server, tests3[i].port, tests3[i].device);
  320. fail_count++;
  321. } else if (0 < verbose) {
  322. printf("spec: '%s' is '%s' '%s' '%s'\n",
  323. tests3[i].spec,
  324. tests3[i].server,
  325. tests3[i].port,
  326. tests3[i].device);
  327. }
  328. }
  329. if (0 < fail_count) {
  330. printf("%s: Error Count: %d\n", "test_gpsdclient", fail_count);
  331. } else if (0 < verbose) {
  332. printf("%s: Pass\n", "test_gpsdclient");
  333. }
  334. exit(fail_count);
  335. }
  336. // vim: set expandtab shiftwidth=4