1(** Corpus tests using ppx_expect for GPX parsing *)
2
3open Gpx
4
5let test_data_dir =
6 let rec find_data_dir current_dir =
7 let data_path = Filename.concat current_dir "data" in
8 let test_data_path = Filename.concat current_dir "test/data" in
9 if Sys.file_exists data_path && Sys.is_directory data_path then
10 data_path
11 else if Sys.file_exists test_data_path && Sys.is_directory test_data_path then
12 test_data_path
13 else
14 let parent = Filename.dirname current_dir in
15 if parent = current_dir then
16 failwith "Could not find test data directory"
17 else
18 find_data_dir parent
19 in
20 find_data_dir (Sys.getcwd ())
21
22let read_test_file filename =
23 let path = Filename.concat test_data_dir filename in
24 In_channel.with_open_text path In_channel.input_all
25
26let%expect_test "parse simple waypoints" =
27 let content = read_test_file "simple_waypoints.gpx" in
28 match parse_string content with
29 | Ok gpx ->
30 let waypoints = Doc.waypoints gpx in
31 Printf.printf "Waypoints count: %d\n" (List.length waypoints);
32 Printf.printf "First waypoint name: %s\n"
33 (match waypoints with
34 | wpt :: _ -> (match Waypoint.name wpt with Some n -> n | None -> "None")
35 | [] -> "None");
36 Printf.printf "Creator: %s\n" (Doc.creator gpx);
37 [%expect {|
38 Waypoints count: 3
39 First waypoint name: San Francisco
40 Creator: mlgpx test suite |}]
41 | Error err ->
42 Printf.printf "Error: %s\n" (Error.to_string err);
43 [%expect.unreachable]
44
45let%expect_test "parse detailed waypoints" =
46 let content = read_test_file "detailed_waypoints.gpx" in
47 match parse_string content with
48 | Ok gpx ->
49 let waypoints = Doc.waypoints gpx in
50 let metadata = Doc.metadata gpx in
51 Printf.printf "Waypoints count: %d\n" (List.length waypoints);
52 Printf.printf "Has metadata time: %b\n"
53 (match metadata with Some md -> Metadata.time md <> None | None -> false);
54 Printf.printf "Has bounds: %b\n"
55 (match metadata with Some md -> Metadata.bounds_opt md <> None | None -> false);
56 (match waypoints with
57 | wpt :: _ ->
58 Printf.printf "First waypoint has elevation: %b\n" (Waypoint.elevation wpt <> None);
59 Printf.printf "First waypoint has time: %b\n" (Waypoint.time wpt <> None);
60 Printf.printf "First waypoint has links: %b\n" (Waypoint.links wpt <> [])
61 | [] -> ());
62 [%expect {|
63 Waypoints count: 2
64 Has metadata time: true
65 Has bounds: true
66 First waypoint has elevation: true
67 First waypoint has time: true
68 First waypoint has links: true |}]
69 | Error _ ->
70 Printf.printf "Parse error\n";
71 [%expect.unreachable]
72
73let%expect_test "parse simple route" =
74 let content = read_test_file "simple_route.gpx" in
75 match parse_string content with
76 | Ok gpx ->
77 let routes = Doc.routes gpx in
78 Printf.printf "Routes count: %d\n" (List.length routes);
79 (match routes with
80 | rte :: _ ->
81 Printf.printf "Route name: %s\n"
82 (match Route.name rte with Some n -> n | None -> "None");
83 Printf.printf "Route points count: %d\n" (Route.point_count rte);
84 Printf.printf "Route has number: %b\n" (Route.number rte <> None)
85 | [] -> ());
86 [%expect {|
87 Routes count: 1
88 Route name: SF to Oakland
89 Route points count: 3
90 Route has number: true |}]
91 | Error _ ->
92 Printf.printf "Parse error\n";
93 [%expect.unreachable]
94
95let%expect_test "parse simple track" =
96 let content = read_test_file "simple_track.gpx" in
97 match parse_string content with
98 | Ok gpx ->
99 let tracks = Doc.tracks gpx in
100 Printf.printf "Tracks count: %d\n" (List.length tracks);
101 (match tracks with
102 | trk :: _ ->
103 Printf.printf "Track name: %s\n"
104 (match Track.name trk with Some n -> n | None -> "None");
105 Printf.printf "Track segments: %d\n" (Track.segment_count trk);
106 let segments = Track.segments trk in
107 (match segments with
108 | seg :: _ ->
109 Printf.printf "First segment points: %d\n" (Track.Segment.point_count seg);
110 let points = Track.Segment.points seg in
111 (match points with
112 | pt :: _ ->
113 Printf.printf "First point has elevation: %b\n" (Waypoint.elevation pt <> None);
114 Printf.printf "First point has time: %b\n" (Waypoint.time pt <> None)
115 | [] -> ())
116 | [] -> ())
117 | [] -> ());
118 [%expect {|
119 Tracks count: 1
120 Track name: Morning Jog
121 Track segments: 1
122 First segment points: 5
123 First point has elevation: true
124 First point has time: true |}]
125 | Error _ ->
126 Printf.printf "Parse error\n";
127 [%expect.unreachable]
128
129let%expect_test "parse multi-segment track" =
130 let content = read_test_file "multi_segment_track.gpx" in
131 match parse_string content with
132 | Ok gpx ->
133 let tracks = Doc.tracks gpx in
134 Printf.printf "Tracks count: %d\n" (List.length tracks);
135 (match tracks with
136 | trk :: _ ->
137 Printf.printf "Track segments: %d\n" (Track.segment_count trk);
138 let total_points = Track.point_count trk in
139 Printf.printf "Total track points: %d\n" total_points
140 | [] -> ());
141 [%expect {|
142 Tracks count: 1
143 Track segments: 2
144 Total track points: 6 |}]
145 | Error _ ->
146 Printf.printf "Parse error\n";
147 [%expect.unreachable]
148
149let%expect_test "parse comprehensive gpx" =
150 let content = read_test_file "comprehensive.gpx" in
151 match parse_string content with
152 | Ok gpx ->
153 let waypoints = Doc.waypoints gpx in
154 let routes = Doc.routes gpx in
155 let tracks = Doc.tracks gpx in
156 let metadata = Doc.metadata gpx in
157 Printf.printf "Waypoints: %d\n" (List.length waypoints);
158 Printf.printf "Routes: %d\n" (List.length routes);
159 Printf.printf "Tracks: %d\n" (List.length tracks);
160 Printf.printf "Has author: %b\n"
161 (match metadata with Some md -> Metadata.author md <> None | None -> false);
162 Printf.printf "Has copyright: %b\n"
163 (match metadata with Some md -> Metadata.copyright md <> None | None -> false);
164 Printf.printf "Has keywords: %b\n"
165 (match metadata with Some md -> Metadata.keywords md <> None | None -> false);
166 [%expect {|
167 Waypoints: 2
168 Routes: 1
169 Tracks: 1
170 Has author: true
171 Has copyright: true
172 Has keywords: true |}]
173 | Error _ ->
174 Printf.printf "Parse error\n";
175 [%expect.unreachable]
176
177let%expect_test "parse minimal gpx" =
178 let content = read_test_file "minimal.gpx" in
179 match parse_string content with
180 | Ok gpx ->
181 Printf.printf "Minimal GPX parsed successfully\n";
182 let waypoints = Doc.waypoints gpx in
183 let routes = Doc.routes gpx in
184 let tracks = Doc.tracks gpx in
185 Printf.printf "Waypoints: %d\n" (List.length waypoints);
186 Printf.printf "Routes: %d\n" (List.length routes);
187 Printf.printf "Tracks: %d\n" (List.length tracks);
188 [%expect {|
189 Minimal GPX parsed successfully
190 Waypoints: 1
191 Routes: 0
192 Tracks: 0 |}]
193 | Error err ->
194 Printf.printf "Error: %s\n" (match err with
195 | Invalid_xml s -> "Invalid XML: " ^ s
196 | _ -> "Other error");
197 [%expect.unreachable]
198
199let%expect_test "parse edge cases" =
200 let content = read_test_file "edge_cases.gpx" in
201 match parse_string content with
202 | Ok gpx ->
203 Printf.printf "Edge cases parsed successfully\n";
204 let waypoints = Doc.waypoints gpx in
205 let tracks = Doc.tracks gpx in
206 Printf.printf "Waypoints: %d\n" (List.length waypoints);
207 Printf.printf "Tracks: %d\n" (List.length tracks);
208 (* Check coordinate ranges *)
209 let check_coords () =
210 match waypoints with
211 | wpt1 :: wpt2 :: wpt3 :: _ ->
212 let lat1, lon1 = Waypoint.to_floats wpt1 in
213 let lat2, lon2 = Waypoint.to_floats wpt2 in
214 let lat3, lon3 = Waypoint.to_floats wpt3 in
215 Printf.printf "South pole coords: %.1f, %.1f\n" lat1 lon1;
216 Printf.printf "North pole coords: %.1f, %.6f\n" lat2 lon2;
217 Printf.printf "Null island coords: %.1f, %.1f\n" lat3 lon3;
218 | _ -> Printf.printf "Unexpected waypoint count\n"
219 in
220 check_coords ();
221 [%expect {|
222 Edge cases parsed successfully
223 Waypoints: 3
224 Tracks: 1
225 South pole coords: -90.0, -180.0
226 North pole coords: 90.0, 179.999999
227 Null island coords: 0.0, 0.0 |}]
228 | Error _ ->
229 Printf.printf "Parse error\n";
230 [%expect.unreachable]
231
232let%expect_test "test validation" =
233 let content = read_test_file "comprehensive.gpx" in
234 match parse_string content with
235 | Ok gpx ->
236 let validation = validate_gpx gpx in
237 Printf.printf "Is valid: %b\n" validation.is_valid;
238 Printf.printf "Issue count: %d\n" (List.length validation.issues);
239 [%expect {|
240 Is valid: true
241 Issue count: 0 |}]
242 | Error _ ->
243 Printf.printf "Parse error\n";
244 [%expect.unreachable]
245
246let%expect_test "round-trip test" =
247 let content = read_test_file "simple_waypoints.gpx" in
248 match parse_string content with
249 | Ok gpx ->
250 (match write_string gpx with
251 | Ok xml_output ->
252 (match parse_string xml_output with
253 | Ok gpx2 ->
254 Printf.printf "Round-trip successful\n";
255 let waypoints = Doc.waypoints gpx in
256 let waypoints2 = Doc.waypoints gpx2 in
257 Printf.printf "Original waypoints: %d\n" (List.length waypoints);
258 Printf.printf "Round-trip waypoints: %d\n" (List.length waypoints2);
259 Printf.printf "Creators match: %b\n" (Doc.creator gpx = Doc.creator gpx2);
260 [%expect.unreachable]
261 | Error _ ->
262 Printf.printf "Round-trip parse failed\n";
263 [%expect.unreachable])
264 | Error _ ->
265 Printf.printf "Write failed\n";
266 [%expect {| Write failed |}])
267 | Error _ ->
268 Printf.printf "Initial parse failed\n";
269 [%expect.unreachable]