GPS Exchange Format library/CLI in OCaml
at main 9.8 kB view raw
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]