From 38819a2edac4869db95ca03a8ad77b6a3fd8186d Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Wed, 27 May 2026 11:08:11 +0100 Subject: [PATCH] Add failing regression tests for edge cases bugs All of these test cases currently fail: - star-empty-match: `*` cannot consume zero characters - match-exhausted-path: ? / [..] / dir-sep should raise an exception when the path is shorter than the pattern - of_string-error: an unclosed `[` raises instead of returning Error - roundtrip-meta: roundtrip fails as `to_string` emits meta chars in String components verbatim These tests are expected to fail at this commit. --- test/test.ml | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/test/test.ml b/test/test.ml index 791e7e3..09f2915 100644 --- a/test/test.ml +++ b/test/test.ml @@ -102,6 +102,54 @@ let test_split () = ] (Glob.path_of_string "/home/bactrian/", Glob.[ star; string ".txt" ]) +let test_star_empty_match () = + let g s = Glob.of_string ~dir_sep s |> Result.get_ok in + let matches g s = Glob.matches g (Glob.path_of_string s) in + Alcotest.(check bool) "*.txt matches .txt" true (matches (g "*.txt") ".txt"); + Alcotest.(check bool) "* matches empty" true (matches (g "*") ""); + Alcotest.(check bool) "a*b matches ab" true (matches (g "a*b") "ab"); + Alcotest.(check bool) "/*/x matches //x" true (matches (g "/*/x") "//x") + +let test_match_exhausted_path () = + let g s = Glob.of_string ~dir_sep s |> Result.get_ok in + let matches g s = + try Glob.matches g (Glob.path_of_string s) + with e -> + Alcotest.failf "matches raised %s on exhausted path" + (Printexc.to_string e) + in + Alcotest.(check bool) "? vs empty" false (matches (g "?") ""); + Alcotest.(check bool) "[a-z] vs empty" false (matches (g "[a-z]") ""); + Alcotest.(check bool) "[!a] vs empty" false (matches (g "[!a]") ""); + Alcotest.(check bool) "a/ vs a" false (matches (g "a/") "a") + +let test_of_string_error () = + match Glob.of_string ~dir_sep "[abc" with + | Ok _ -> Alcotest.fail "expected Error for unclosed character class" + | Error _ -> () + | exception e -> + Alcotest.failf "of_string raised %s instead of returning Error" + (Printexc.to_string e) + +let test_roundtrip_meta () = + let check_roundtrip components path expected_match = + let g = Glob.of_components ~dir_sep components in + let s = Glob.to_string g in + match Glob.of_string ~dir_sep s with + | Error e -> Alcotest.failf "round-trip of %S failed: %s" s e + | Ok g' -> + let p = Glob.path_of_string path in + Alcotest.(check bool) + (Fmt.str "%S vs %S after round-trip" s path) + expected_match (Glob.matches g' p) + in + check_roundtrip Glob.[ string "[meta]" ] "[meta]" true; + check_roundtrip Glob.[ string "[meta]" ] "ameta]" false; + check_roundtrip Glob.[ string "*.txt" ] "*.txt" true; + check_roundtrip Glob.[ string "*.txt" ] "anything.txt" false; + check_roundtrip Glob.[ string "a?b" ] "a?b" true; + check_roundtrip Glob.[ string "a?b" ] "aXb" false + let simple_tests = [ ("globs", `Quick, test_globs); @@ -109,4 +157,14 @@ let simple_tests = ("splitting", `Quick, test_split); ] -let () = Alcotest.run "glob" [ ("simple", simple_tests) ] +let regression_tests = + [ + ("star-empty-match", `Quick, test_star_empty_match); + ("match-exhausted-path", `Quick, test_match_exhausted_path); + ("of_string-error", `Quick, test_of_string_error); + ("roundtrip-meta", `Quick, test_roundtrip_meta); + ] + +let () = + Alcotest.run "glob" + [ ("simple", simple_tests); ("regressions", regression_tests) ] -- 2.51.2