open Re.Glob
open Fort_unit

let re_match ?pos ?len re s = Re.execp ?pos ?len (Re.compile re) s
let re_mismatch ?pos ?len re s = not (re_match ?pos ?len re s)

let _ =
  assert (re_match (glob "foo*") "foobar");
  assert (re_mismatch (glob "fo?bar") "fobar");
  assert (re_match (glob "fo?bar") "foobar");
  assert (re_mismatch (glob "fo?bar") "foo0bar");
  assert (re_match (glob "?oobar") "foobar");
  assert (re_match (glob "*bar") "foobar");
  assert (re_mismatch (glob "\\*bar") "foobar");
  assert (re_match (glob "\\*bar") "*bar");
  assert (re_match (glob "[ab]foo") "afoo");
  assert (re_match (glob "[ab]foo") "bfoo");
  assert (re_mismatch (glob "[ab]foo") "cfoo");
  assert (re_mismatch (glob "c[ab]foo") "cabfoo");
  assert (re_match (glob ".foo") ".foo");
  assert (re_mismatch (glob ".foo") "afoo");
  assert (re_match (glob "*[.]foo") "a.foo");
  assert (re_match (glob "*[.]foo") "ba.foo");
  assert (re_mismatch (glob "*.foo") ".foo");
  assert (re_mismatch (glob "*[.]foo") ".foo");
  assert (re_match (glob ~anchored:true "*/foo") "/foo");
  assert (re_match (glob ~anchored:true "foo/*") "foo/");
  assert (re_mismatch (glob "/[^f]") "/foo");
  assert (re_match (glob "/[^f]") "/bar");
  assert (re_mismatch (glob ~anchored:true "/[^f]") "/bar");
  assert (re_mismatch (glob ~anchored:true "*") ".bar");
  assert (re_match (glob "foo[.]bar") "foo.bar");
  assert (re_mismatch (glob "[.]foo") ".foo");
  assert (re_mismatch (glob "foo[/]bar") "foo/bar");
  assert (re_match (glob ~anchored:true "*bar") "foobar");
  assert (re_match (glob "foo") "foobar");
  assert (re_match (glob "bar") "foobar");
  assert (re_mismatch (glob ~anchored:true "foo") "foobar");
  assert (re_mismatch (glob ~anchored:true "bar") "foobar");
  assert (re_mismatch (glob "{foo,bar}bar") "foobar");
  assert (re_match (glob "{foo,bar}bar") "{foo,bar}bar");
  assert (re_mismatch (glob "foo?bar") "foo/bar");
  let pathname = true in
  let period = true in
  assert (re_mismatch (glob ~pathname ~period "?oobar") ".oobar");
  assert (re_mismatch (glob ~pathname ~period "?oobar") "/oobar");
  assert (re_mismatch (glob ~pathname ~period "f?obar") "f/obar");
  assert (re_match (glob ~pathname ~period "f?obar") "f.obar");
  assert (re_match (glob ~pathname ~period "f*.bar") "f.bar");
  assert (re_match (glob ~pathname ~period "f?.bar") "fo.bar");
  assert (re_match (glob ~pathname ~period "/.bar") "/.bar");
  assert (re_mismatch (glob ~pathname ~period "*.bar") ".bar");
  assert (re_mismatch (glob ~pathname ~period "?") ".");
  assert (re_mismatch (glob ~pathname ~period "/*bar") "/.bar");
  assert (re_mismatch (glob "?oobar") ".oobar");
  assert (re_mismatch (glob "?oobar") "/oobar");
  let pathname = true in
  let period = false in
  assert (re_mismatch (glob ~pathname ~period "?oobar") "/oobar");
  assert (re_match (glob ~pathname ~period "?oobar") ".oobar");
  assert (re_mismatch (glob ~pathname ~period "f?obar") "f/obar");
  assert (re_match (glob ~pathname ~period "f?obar") "f.obar");
  let pathname = false in
  let period = false in
  assert (re_match (glob ~pathname ~period "?oobar") ".oobar");
  assert (re_match (glob ~pathname ~period "?oobar") "/oobar");
  assert (re_match (glob ~expand_braces:true "{foo,far}bar") "foobar");
  assert (re_match (glob ~expand_braces:true "{foo,far}bar") "farbar");
  assert (re_mismatch (glob ~expand_braces:true "{foo,far}bar") "{foo,far}bar");
  (* Double asterisk *)
  let anchored = true in
  assert (re_match (glob ~anchored "**") "foobar");
  assert (re_match (glob ~anchored "**") "foo/bar");
  assert (re_match (glob ~anchored "**/bar") "foo/bar");
  assert (re_match (glob ~anchored "**/bar") "foo/far/bar");
  assert (re_mismatch (glob ~anchored "foo/**") "foo");
  assert (re_match (glob ~anchored "foo/**") "foo/bar");
  assert (re_match (glob ~anchored "foo/**") "foo/far/bar");
  assert (re_match (glob ~anchored "foo/**/bar") "foo/far/bar");
  assert (re_match (glob ~anchored "foo/**/bar") "foo/far/oof/bar");
  assert (re_match (glob ~anchored "foo/**bar") "foo/far/oofbar");
  assert (re_match (glob ~anchored "foo/**bar") "foo/bar");
  assert (re_match (glob ~anchored "foo/**bar") "foo/foobar");
  assert (re_match (glob ~anchored "/**") "//foo");
  assert (re_match (glob ~anchored "/**") "/");
  assert (re_match (glob ~anchored "/**") "/x");
  assert (re_match (glob ~anchored "**") "foo//bar");
  assert (re_match (glob ~anchored "foo/bar/**/*.ml") "foo/bar/baz/foobar.ml");
  assert (re_match (glob ~anchored "foo/bar/**/*.ml") "foo/bar/foobar.ml");
  assert (re_match (glob ~anchored "foo/**/bar/**/baz") "foo/bar/baz");
  assert (re_match (glob ~anchored "foo/**/bar/**/baz") "foo/bar/x/y/z/baz");
  assert (re_match (glob ~anchored "foo/**/bar/**/baz") "foo/x/y/z/bar/baz");
  assert (re_match (glob ~anchored "foo/**/bar/**/baz") "foo/bar/x/bar/x/baz");
  assert (re_mismatch (glob ~anchored "foo/**/bar/**/baz") "foo/bar/../x/baz");
  assert (re_mismatch (glob ~anchored "foo/**/bar/**/baz") "foo/bar/./x/baz");
  (* Interaction with [~period] *)
  let period = true in
  assert (re_mismatch (glob ~anchored ~period "**") ".foobar");
  assert (re_mismatch (glob ~anchored ~period "**") ".foo/bar");
  assert (re_mismatch (glob ~anchored ~period "foo/**") "foo/.bar");
  assert (re_mismatch (glob ~anchored ~period "**") "foo/.bar/bat");
  assert (re_mismatch (glob ~anchored ~period "foo/**/bat") "foo/.bar/bat");
  assert (re_mismatch (glob ~anchored ~period "/**/bat") "/foo/.bar/bat");
  assert (re_mismatch (glob ~anchored ~period "/**/bat") "/.bar/bat");
  assert (re_mismatch (glob ~anchored ~period "/**bat") "/bar/.bat");
  assert (re_match (glob ~anchored ~period ".**") ".foobar");
  assert (re_match (glob ~anchored ~period ".**") ".foo/bar");
  assert (re_match (glob ~anchored ~period "foo/.**") "foo/.bar");
  let period = false in
  assert (re_match (glob ~anchored ~period "**") ".foobar");
  assert (re_match (glob ~anchored ~period "**") ".foo/bar");
  assert (re_match (glob ~anchored ~period "foo/**") "foo/.bar");
  assert (re_match (glob ~anchored ~period "**") "foo/.bar/bat");
  assert (re_match (glob ~anchored ~period "foo/**/bat") "foo/.bar/bat");
  assert (re_match (glob ~anchored ~period "/**/bat") "/foo/.bar/bat");
  assert (re_match (glob ~anchored ~period "/**/bat") "/.bar/bat");
  assert (re_match (glob ~anchored ~period "/**bat") "/bar/.bat");
  (* Backslash handling *)
  let anchored = true in
  let match_backslashes = false in
  assert (re_mismatch (glob ~anchored ~match_backslashes "a/b/c") "a\\b/c");
  assert (re_match (glob ~anchored ~match_backslashes "a\\b") "ab");
  assert (re_match (glob ~anchored ~match_backslashes "a/*.ml") "a/b\\c.ml");
  assert (re_mismatch (glob ~anchored ~match_backslashes "a/b/*.ml") "a\\b\\c.ml");
  assert (re_mismatch (glob ~anchored ~match_backslashes "/") "\\");
  assert (re_mismatch (glob ~anchored ~match_backslashes "/?") "\\a");
  assert (re_match (glob ~anchored ~match_backslashes "a/**.ml") "a\\c\\.b.ml");
  let match_backslashes = true in
  assert (re_match (glob ~anchored ~match_backslashes "a/b/c") "a\\b/c");
  assert (re_match (glob ~anchored ~match_backslashes "a\\b") "ab");
  assert (re_mismatch (glob ~anchored ~match_backslashes "a/*.ml") "a/b\\c.ml");
  assert (re_match (glob ~anchored ~match_backslashes "a/b/*.ml") "a\\b\\c.ml");
  assert (re_match (glob ~anchored ~match_backslashes "/") "\\");
  assert (re_match (glob ~anchored ~match_backslashes "/?") "\\a");
  assert (re_mismatch (glob ~anchored ~match_backslashes "a/**.ml") "a\\c\\.b.ml");
  run_test_suite "test_re"
;;
