Skip to content

Commit

Permalink
Merge pull request ocaml#4966 from rjbou/reftests
Browse files Browse the repository at this point in the history
Reftests: some updates
  • Loading branch information
rjbou committed Jul 11, 2022
1 parent 0ca95b2 commit 010f966
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 77 deletions.
6 changes: 6 additions & 0 deletions master_changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ New option/command/subcommand are prefixed with ◈.

## Reftests
### Tests
### Engine
* Fix meld reftest: open only with failing ones [#4913 @rjbou]
* Add `BASEDIR` to environement [#4913 @rjbou]
* Replace opam bin path [#4913 @rjbou]
Expand All @@ -104,6 +105,11 @@ New option/command/subcommand are prefixed with ◈.
* Hackish way to have several replacement in a single line [#4913 @rjbou]
* Substitution in regexp pattern (for environment variables) [#4913 @rjbou]
* Substitution for opam-cat content [#4913 @rjbou]
* Allow one char package name on repo [#4966 @AltGr]
* Remove opam output beginning with `###` [#4966 @AltGr]
* Add `<pin:path>` header to specify incomplete opam files to pin, it is updated from a template in reftest run (no lint errors) [#4966 @rjbou]
* Unescape output [#4966 @rjbou]
* Clean outputs from opam error reporting block [#4966 @rjbou]
* Fix github url: `git://` form no more handled [#5097 @rjbou]

## Doc
Expand Down
1 change: 1 addition & 0 deletions tests/reftests/opamroot-versions.test
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ let _ =
List.iter (write (Sys.getcwd ())) local
| _ -> ()
### rm -rf $OPAMROOT
### OPAMSYSCOMP=2
### opam init -na default ./default --bare --bypass-checks --no-opamrc --debug-level=0
No configuration file found, using built-in defaults.

Expand Down
233 changes: 156 additions & 77 deletions tests/reftests/run.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
add this package to `default` repository in `./REPO`
- use `### <pkg:NAME.VERSION:FILENAME>`, then the contents below to add this
file as a extra-file of the given package in the `default` repository
- use `### <pin:path>, then the contents below to create a minimal opam
file, it is extended by template defined fields to pin it without lint
errors
- `### FOO=x BAR=y` to export variables for subsequent commands
- shell-like command handling:
* **NO pattern expansion, shell pipes, sequences or redirections**
Expand Down Expand Up @@ -61,7 +64,7 @@ let is_prefix pfx s =
String.sub s 0 (String.length pfx) = pfx

let rem_prefix pfx s =
if not (is_prefix pfx s) then invalid_arg "rem_prefix"
if not (is_prefix pfx s) || s = pfx then invalid_arg "rem_prefix"
else String.sub s (String.length pfx) (String.length s - String.length pfx)

(* Test file format: {v
Expand Down Expand Up @@ -133,7 +136,14 @@ type filt_sort =
| Grep
| GrepV

let str_replace_path ?(escape=false) whichway filters s =
let str_replace_path ?escape whichway filters s =
let unescape = escape = Some false in
let escape = escape = Some true in
let s =
if unescape then
Re.(replace_string (compile @@ str "\\\\") ~by:"\\" s)
else s
in
let escape =
if escape then Re.(replace_string (compile @@ char '\\') ~by:"\\\\")
else fun s -> s
Expand Down Expand Up @@ -200,7 +210,7 @@ let command
let rec filter_output ?(first=true) ic =
match input_line ic with
| s ->
let s = str_replace_path OpamSystem.back_to_forward filter s in
let s = str_replace_path ~escape:false OpamSystem.back_to_forward filter s in
if s = "\\c" then filter_output ~first ic
else
(if not first then Buffer.add_char out_buf '\n';
Expand Down Expand Up @@ -269,6 +279,7 @@ let rec with_temp_dir f =

type command =
| File_contents of string
| Pin_file_content of string
| Cat of { files: string list;
filter: (Re.t * filt_sort) list; }
| Run of { env: (string * string) list;
Expand Down Expand Up @@ -323,7 +334,7 @@ module Parse = struct
let re_package =
seq [
str "<pkg:";
group @@ seq [ alpha; rep1 @@ alt [ alnum; set "_-+" ]];
group @@ seq [ alpha; rep @@ alt [ alnum; set "_-+" ]];
char '.';
group @@ rep1 @@ alt [ alnum; set "-_+.~" ];
opt @@ seq [ char ':' ; group @@ rep1 @@ alt [ alnum; set "-_+.~" ]];
Expand All @@ -332,6 +343,9 @@ module Parse = struct

let command ?(vars=[]) str =
if str.[0] = '<' && str.[String.length str - 1] = '>' then
if String.length str > 4 && String.sub str 1 4 = "pin:" then
Pin_file_content (String.sub str 5 (String.length str - 6))
else
let f =
try
let grs = exec (compile re_package) str in
Expand Down Expand Up @@ -426,18 +440,30 @@ let parse_command = Parse.command
let common_filters ?opam dir =
let tmpdir = Filename.get_temp_dir_name () in
let open Re in
[
alt [str dir; str (OpamSystem.back_to_forward dir)],
Sed "${BASEDIR}";
seq [opt (str "/private");
alt [str tmpdir;
str (OpamSystem.back_to_forward tmpdir)];
rep (set "/\\");
str "opam-";
rep1 (alt [xdigit; char '-'])],
Sed "${OPAMTMP}";
] @
(match opam with
[
seq [ bol;
alt [ str "#=== ERROR";
seq [ str "# "; alt @@ List.map str
[ "context";
"path";
"command";
"exit-code";
"env-file";
"output-file"]]]],
GrepV;
seq [bol; str cmd_prompt],
Sed "##% ";
alt [str dir; str (OpamSystem.back_to_forward dir)],
Sed "${BASEDIR}";
seq [opt (str "/private");
alt [str tmpdir;
str (OpamSystem.back_to_forward tmpdir)];
rep (set "/\\");
str "opam-";
rep1 (alt [xdigit; char '-'])],
Sed "${OPAMTMP}";
] @
(match opam with
| None -> []
| Some opam -> [ str opam, Sed "${OPAMBIN}" ])

Expand Down Expand Up @@ -476,6 +502,72 @@ let rec list_remove x = function
| [] -> []
| y :: r -> if x = y then r else y :: list_remove x r


let print_opamfile file =
try
let open OpamParserTypes.FullPos in
let original = OpamParser.FullPos.file file in
let rec mangle item =
match item.pelem with
| Section s ->
{item with
pelem =
Section {s with
section_name =
OpamStd.Option.map (fun v ->
{v with pelem = mangle_string v.pelem})
s.section_name;
section_items =
{s.section_items with
pelem = List.map mangle s.section_items.pelem}}}
| Variable(name, value) ->
{item with pelem = Variable(name, mangle_value value)}
and mangle_value item =
match item.pelem with
| String s ->
{item with pelem = String(mangle_string s)}
| Relop(op, l, r) ->
{item with pelem = Relop(op, mangle_value l, mangle_value r)}
| Prefix_relop(relop, v) ->
{item with pelem = Prefix_relop(relop, mangle_value v)}
| Logop(op, l, r) ->
{item with pelem = Logop(op, mangle_value l, mangle_value r)}
| Pfxop(op, v) ->
{item with pelem = Pfxop(op, mangle_value v)}
| List l ->
{item with pelem = List{l with pelem = List.map mangle_value l.pelem}}
| Group l ->
{item with pelem = Group{l with pelem = List.map mangle_value l.pelem}}
| Option(v, l) ->
{item with pelem = Option(mangle_value v, {l with pelem = List.map mangle_value l.pelem})}
| Env_binding(name, op, v) ->
{item with pelem = Env_binding(name, op, mangle_value v)}
| Bool _
| Int _
| Ident _ -> item
and mangle_string = String.map (function '\\' -> '/' | c -> c)
in
let mangled =
{original with file_contents = List.map mangle original.file_contents}
in
OpamPrinter.FullPos.Normalise.opamfile mangled
with
| Sys_error _ -> Printf.sprintf "# %s not found" file
| e -> Printf.sprintf "# Error on file %s: %s" file (Printexc.to_string e)

let template_opamfile =
OpamParser.FullPos.string {|
opam-version: "2.0"
synopsis: "A word"
description: "Two words."
authors: "the testing team"
homepage: "egapemoh"
maintainer: "maint@tain.er"
license: "ISC"
dev-repo: "hg+htpps://to@lo.ck"
bug-reports: "https://nobug"
|} "<nofile>"

let run_test ?(vars=[]) ~opam t =
let opamroot0 = Filename.concat (Sys.getcwd ()) ("root-"^t.repo_hash) in
with_temp_dir @@ fun dir ->
Expand Down Expand Up @@ -510,76 +602,63 @@ let run_test ?(vars=[]) ~opam t =
write_file ~path ~contents;
print_string contents;
vars
| Pin_file_content path ->
let open OpamParserTypes.FullPos in
let raw_content = (String.concat "\n" out) in
let opamfile = OpamParser.FullPos.string raw_content path in
let nullify_pos p =
{p with pos = { filename = path; start = -1, -1; stop = -1, -1; }}
in
let test_content, tpl_content =
List.fold_left (fun (test_content, tpl_content) item ->
match item with
| { pelem = Variable (name, _); _} ->
let tpl_overwrite, test_content =
List.partition (function
| { pelem = Variable (n, _); _} -> n.pelem = name.pelem
| _ -> false)
test_content
in
let item =
match tpl_overwrite with
| [ item ] -> item
| _ -> item
in
test_content, item::tpl_content
| { pelem = Section _ ; _} -> test_content, item::tpl_content
)
(opamfile.file_contents,[]) template_opamfile.file_contents
in
let file_contents =
List.rev_map nullify_pos tpl_content
@ List.map nullify_pos test_content
in
let contents =
Printf.sprintf "%s\n"
(OpamPrinter.FullPos.opamfile { opamfile with file_contents })
in
write_file ~path ~contents;
print_string (raw_content ^ "\n");
vars
| Export bindings ->
List.fold_left
(fun vars (v, r) -> (v, r) :: List.filter (fun (w, _) -> v <> w) vars)
vars bindings
| Cat { files; filter } ->
let print_opamfile header file =
let content =
let open OpamParserTypes.FullPos in
let original = OpamParser.FullPos.file file in
let rec mangle item =
match item.pelem with
| Section s ->
{item with
pelem =
Section {s with
section_name =
OpamStd.Option.map (fun v ->
{v with pelem = mangle_string v.pelem})
s.section_name;
section_items =
{s.section_items with
pelem = List.map mangle s.section_items.pelem}}}
| Variable(name, value) ->
{item with pelem = Variable(name, mangle_value value)}
and mangle_value item =
match item.pelem with
| String s ->
{item with pelem = String(mangle_string s)}
| Relop(op, l, r) ->
{item with pelem = Relop(op, mangle_value l, mangle_value r)}
| Prefix_relop(relop, v) ->
{item with pelem = Prefix_relop(relop, mangle_value v)}
| Logop(op, l, r) ->
{item with pelem = Logop(op, mangle_value l, mangle_value r)}
| Pfxop(op, v) ->
{item with pelem = Pfxop(op, mangle_value v)}
| List l ->
{item with pelem = List{l with pelem = List.map mangle_value l.pelem}}
| Group l ->
{item with pelem = Group{l with pelem = List.map mangle_value l.pelem}}
| Option(v, l) ->
{item with pelem = Option(mangle_value v, {l with pelem = List.map mangle_value l.pelem})}
| Env_binding(name, op, v) ->
{item with pelem = Env_binding(name, op, mangle_value v)}
| Bool _
| Int _
| Ident _ -> item
and mangle_string = String.map (function '\\' -> '/' | c -> c)
in
let mangled =
{original with file_contents = List.map mangle original.file_contents}
in
OpamPrinter.FullPos.Normalise.opamfile mangled
in
let str = if header then Printf.sprintf "=> %s <=\n" file else "" in
let str = Printf.sprintf "%s%s" str content in
let str =
str_replace_path OpamSystem.back_to_forward
(filter @ common_filters dir) str
in
print_string str
in
let files =
List.map (fun s -> Re.(replace_string (compile @@ str "$OPAMROOT")
~by:opamroot s)) files
in
(match files with
| file::[] -> print_opamfile false file
| _::_ -> List.iter (print_opamfile true) files
| [] -> ());
let s =
match files with
| [file] -> print_opamfile file
| files ->
OpamStd.List.concat_map "\n"
(fun f -> Printf.sprintf "=> %s <=\n%s" f (print_opamfile f))
files
in
print_string (str_replace_path OpamSystem.back_to_forward
(filter @ common_filters dir) s);
vars
| Run {env; cmd; args; filter; output; unordered} ->
let silent = output <> None || unordered in
Expand Down

0 comments on commit 010f966

Please sign in to comment.