Skip to content

Commit b312070

Browse files
v0.17~preview.129.07+242
1 parent d359469 commit b312070

36 files changed

+518
-208
lines changed

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License
22

3-
Copyright (c) 2015--2023 Jane Street Group, LLC <[email protected]>
3+
Copyright (c) 2015--2024 Jane Street Group, LLC <[email protected]>
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

config/dune

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
(library (name expect_test_config) (public_name ppx_expect.config)
1+
(library
2+
(name expect_test_config)
3+
(public_name ppx_expect.config)
24
(synopsis "Default runtime configuration for ppx_expect")
3-
(libraries expect_test_config_types) (preprocess no_preprocessing))
5+
(libraries expect_test_config_types)
6+
(preprocess no_preprocessing))

config/types/dune

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
(library (name expect_test_config_types)
1+
(library
2+
(name expect_test_config_types)
23
(public_name ppx_expect.config_types)
3-
(synopsis "Runtime configuration options for ppx_expect") (libraries)
4-
(preprocess no_preprocessing))
4+
(synopsis "Runtime configuration options for ppx_expect")
5+
(libraries)
6+
(preprocess no_preprocessing))

dune-project

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
(lang dune 1.11)
1+
(lang dune 2.0)
2+
3+
(formatting disabled)

evaluator/dune

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
(library (name ppx_expect_evaluator) (public_name ppx_expect.evaluator)
2-
(libraries) (preprocess no_preprocessing) (library_flags -linkall))
1+
(library
2+
(name ppx_expect_evaluator)
3+
(public_name ppx_expect.evaluator)
4+
(libraries)
5+
(preprocess no_preprocessing)
6+
(library_flags -linkall))

make-corrected-file/dune

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
(library (name make_corrected_file)
1+
(library
2+
(name make_corrected_file)
23
(public_name ppx_expect.make_corrected_file)
3-
(libraries base ppxlib.print_diff stdio) (preprocess no_preprocessing))
4+
(libraries base ppxlib.print_diff stdio)
5+
(preprocess no_preprocessing))

runtime/dune

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
(library (name ppx_expect_runtime) (public_name ppx_expect.runtime)
1+
(library
2+
(foreign_stubs
3+
(language c)
4+
(names ppx_expect_runtime_stubs))
5+
(name ppx_expect_runtime)
6+
(public_name ppx_expect.runtime)
27
(libraries base stdio ppx_inline_test.runtime-lib make_corrected_file
3-
expect_test_config)
4-
(c_names ppx_expect_runtime_stubs)
5-
(js_of_ocaml (javascript_files runtime.js)) (preprocess no_preprocessing))
8+
expect_test_config)
9+
(js_of_ocaml
10+
(javascript_files runtime.js))
11+
(preprocess no_preprocessing))

runtime/expectation.ml

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,31 @@ let formatter
3636
} :
3737
(output, behavior) t)
3838
=
39+
let count_leading_spaces line =
40+
line |> String.to_list |> List.take_while ~f:(Char.( = ) ' ') |> List.length
41+
in
3942
Output.Formatter.create
4043
@@ fun str ->
4144
let lines =
42-
(* Whitespace splitting/stripping specifically targets ['\n'] and [' '] so that
43-
unusual characters like ['\r'] and ['\t'] get displayed explicitly in
44-
expectations. *)
45+
(* In pretty payloads, we normalize all newlines to ['\n']. [[%expect_exact ""]]
46+
can be used in cases where a user wants to inspect the whitespace produced by
47+
their output more closely. *)
4548
let stripped =
4649
str
47-
|> String.split ~on:'\n'
48-
|> List.map ~f:(String.rstrip ~drop:(Char.equal ' '))
50+
|> String.split_lines
51+
|> List.map ~f:(String.rstrip ~drop:Char.is_whitespace)
4952
|> List.drop_while ~f:String.is_empty
5053
|> List.rev
5154
|> List.drop_while ~f:String.is_empty
5255
|> List.rev
5356
in
5457
let indent_and_contents =
5558
List.map stripped ~f:(fun line ->
56-
let unindented = String.lstrip ~drop:(Char.equal ' ') line in
57-
String.length line - String.length unindented, unindented)
59+
(* The legacy behavior is to only count the longest prefix of actual spaces
60+
([' ']) for indentation, but to strip all whitespace (including, e.g., ['\t']).
61+
Note that this means [" \t contents"] is counted as having contents
62+
["contents"] and indentation [1]. *)
63+
count_leading_spaces line, String.strip line)
5864
in
5965
match
6066
indent_and_contents
@@ -216,23 +222,23 @@ let expect_no_uncaught_exn virtual_loc =
216222
module For_apply_style = struct
217223
let format_payload mk_node =
218224
Staged.stage
219-
@@ fun ~expect_node_formatting ~loc tag contents ->
225+
@@ fun ~expect_node_formatting ~payload_loc ~loc tag contents ->
226+
let node =
227+
mk_node ~payload_loc:(Some payload_loc) ({ tag; contents } : _ Payload.t) loc
228+
in
220229
let formatted_contents =
221-
Output.Formatter.apply
222-
(formatter
223-
~expect_node_formatting
224-
(mk_node ~payload_loc:None ({ tag; contents } : _ Payload.t) loc))
225-
contents
230+
Output.Formatter.apply (formatter ~expect_node_formatting node) contents
231+
in
232+
let node_shape =
233+
match node.on_incorrect_output with
234+
| T { hand = Longhand; name = _; kind = _ } -> None
235+
| node_shape -> Some node_shape
226236
in
227237
match Output.reconcile ~expected_output:contents ~test_output:formatted_contents with
228238
| Pass -> None
229239
| Fail contents ->
230240
Some
231-
(Output.to_source_code_string
232-
~expect_node_formatting
233-
~node_shape:None
234-
~tag
235-
contents)
241+
(Output.to_source_code_string ~expect_node_formatting ~node_shape ~tag contents)
236242
;;
237243

238244
let format_expect_payload = format_payload expect |> Staged.unstage

runtime/expectation_intf.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ module type Expectation = sig
169169
module For_apply_style : sig
170170
type format_payload :=
171171
expect_node_formatting:Expect_node_formatting.t
172+
-> payload_loc:Compact_loc.t
172173
-> loc:Compact_loc.t
173174
-> String_node_format.Delimiter.t
174175
-> string

runtime/test_block.ml

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ module Current_test : sig
175175
val current_test : unit -> Shared.t option
176176
val current_test_exn : unit -> Shared.t
177177
val iter : f:(t -> unit) -> unit
178+
val assert_no_test_running : basename:string -> line_number:int -> unit
178179
end = struct
179180
type t =
180181
{ line_number : int
@@ -194,6 +195,33 @@ end = struct
194195

195196
let current_test_exn () = Option.value_exn (current_test ())
196197
let iter ~f = Option.iter !test_is_running ~f
198+
199+
let assert_no_test_running ~basename ~line_number =
200+
iter
201+
~f:
202+
(fun
203+
{ line_number = outer_line_number
204+
; basename = outer_basename
205+
; location = _
206+
; test_block = _
207+
}
208+
->
209+
let sexp_here ~basename ~line_number : Sexp.t =
210+
List
211+
[ List [ Atom "file"; sexp_of_string basename ]
212+
; List [ Atom "line"; sexp_of_int line_number ]
213+
]
214+
in
215+
raise_s
216+
(Sexp.message
217+
"Expect_test_runtime: reached one [let%expect_test] from another. Nesting \
218+
expect\n\
219+
tests is prohibited."
220+
[ ( "outer_test"
221+
, sexp_here ~basename:outer_basename ~line_number:outer_line_number )
222+
; "inner_test", sexp_here ~basename ~line_number
223+
]))
224+
;;
197225
end
198226

199227
(* The main testing functions of a test block, which depend on configurations. *)
@@ -244,6 +272,9 @@ module Make (C : Expect_test_config_types.S) = struct
244272
=
245273
let ({ start_bol; start_pos; end_pos } : Compact_loc.t) = location in
246274
let basename = Stdlib.Filename.basename filename_rel_to_project_root in
275+
(* Even if the current tag set indicates this test should be dropped, check that it
276+
wasn't reached from another expect test *)
277+
Current_test.assert_no_test_running ~basename ~line_number;
247278
Ppx_inline_test_lib.test
248279
~config:inline_test_config
249280
~descr:(lazy (Option.value description ~default:""))
@@ -290,9 +321,8 @@ module Make (C : Expect_test_config_types.S) = struct
290321
~expect_node_formatting:Expect_node_formatting.default
291322
~original_file_contents))
292323
in
293-
(* To avoid capturing not-yet flushed data of the stdout/stderr buffers. Lifting
294-
into the provided [IO] monad is required to preserve legacy behavior. *)
295-
C.run (fun () -> C.IO.return (Shared.flush ()));
324+
(* To avoid capturing not-yet flushed data of the stdout/stderr buffers. *)
325+
Shared.flush ();
296326
(* Redirect stdout/stderr *)
297327
let test_block = Shared.set_up_block absolute_filename in
298328
(* Run the test *)

0 commit comments

Comments
 (0)