Skip to content

Commit 9840ac2

Browse files
author
Yuki Ito
committed
capture_io captures a prompt when capturing of stdio
1 parent bcfc927 commit 9840ac2

File tree

2 files changed

+63
-29
lines changed

2 files changed

+63
-29
lines changed

lib/ex_unit/lib/ex_unit/capture_io.ex

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ defmodule ExUnit.CaptureIO do
2828
named device like `:stderr` is also possible globally by
2929
giving the registered device name explicitly as argument.
3030
31+
When capturing of `:stdio`, this function captures a prompt,
32+
otherwise do not.
33+
3134
A developer can set a string as an input. The default
3235
input is `:eof`.
3336
@@ -40,9 +43,9 @@ defmodule ExUnit.CaptureIO do
4043
iex> capture_io(:stderr, fn -> IO.write(:stderr, "josé") end) == "josé"
4144
true
4245
iex> capture_io("this is input", fn->
43-
...> input = IO.gets ""
46+
...> input = IO.gets ">"
4447
...> IO.write input
45-
...> end) == "this is input"
48+
...> end) == ">this is input"
4649
true
4750
4851
"""
@@ -68,7 +71,7 @@ defmodule ExUnit.CaptureIO do
6871

6972
defp do_capture_io(:standard_io, input, fun) do
7073
original_gl = :erlang.group_leader
71-
capture_gl = new_group_leader(self, input)
74+
capture_gl = new_group_leader(self, input, true)
7275
:erlang.group_leader(capture_gl, self)
7376

7477
try do
@@ -105,12 +108,13 @@ defmodule ExUnit.CaptureIO do
105108
end
106109
end
107110

108-
defp new_group_leader(runner, input) do
109-
spawn_link(fn -> group_leader_process(runner, input) end)
111+
defp new_group_leader(runner, input, prompt_config // false) do
112+
spawn_link(fn -> group_leader_process(runner, input, prompt_config) end)
110113
end
111114

112-
defp group_leader_process(runner, input) do
115+
defp group_leader_process(runner, input, prompt_config) do
113116
register_input(input)
117+
register_prompt_config(prompt_config)
114118
group_leader_loop(runner, :infinity, [])
115119
end
116120

@@ -123,6 +127,10 @@ defmodule ExUnit.CaptureIO do
123127
set_input(chars)
124128
end
125129

130+
defp register_prompt_config(bool) do
131+
Process.put(:capture_io_prompt_config, bool)
132+
end
133+
126134
defp set_input(:eof) do
127135
set_input([])
128136
end
@@ -135,6 +143,10 @@ defmodule ExUnit.CaptureIO do
135143
Process.get(:capture_io_input)
136144
end
137145

146+
defp need_prompt? do
147+
Process.get(:capture_io_prompt_config)
148+
end
149+
138150
defp group_leader_loop(runner, wait, buf) do
139151
receive do
140152
{ :io_request, from, reply_as, req } ->
@@ -181,28 +193,42 @@ defmodule ExUnit.CaptureIO do
181193
io_request({ :put_chars, mod, func, args }, buf)
182194
end
183195

184-
defp io_request({ :get_chars, _enc, _prompt, n }, buf) when n >= 0 do
185-
{ get_chars(n), buf }
196+
defp io_request({ :get_chars, _enc, prompt, n }, buf) when n >= 0 do
197+
io_request({ :get_chars, prompt, n }, buf)
186198
end
187199

188-
defp io_request({ :get_chars, _prompt, n }, buf) when n >= 0 do
200+
defp io_request({ :get_chars, prompt, n }, buf) when n >= 0 do
201+
if need_prompt? do
202+
buf = [prompt|buf]
203+
end
204+
189205
{ get_chars(n), buf }
190206
end
191207

192-
defp io_request({ :get_line, _prompt }, buf) do
193-
{ get_line, buf }
208+
defp io_request({ :get_line, _enc, prompt }, buf) do
209+
io_request({ :get_line, prompt }, buf)
194210
end
195211

196-
defp io_request({ :get_line, _enc, _prompt }, buf) do
212+
defp io_request({ :get_line, prompt }, buf) do
213+
if need_prompt? do
214+
buf = [prompt|buf]
215+
end
216+
197217
{ get_line, buf }
198218
end
199219

200-
defp io_request({ :get_until, _prompt, mod, fun, args }, buf) do
201-
{ get_until(mod, fun, args), buf }
220+
defp io_request({ :get_until, _encoding, prompt, mod, fun, args}, buf) do
221+
io_request({ :get_until, prompt, mod, fun, args}, buf)
202222
end
203223

204-
defp io_request({ :get_until, _encoding, _prompt, mod, fun, args}, buf) do
205-
{ get_until(mod, fun, args), buf }
224+
defp io_request({ :get_until, prompt, mod, fun, args }, buf) do
225+
{ result, count } = get_until(mod, fun, args)
226+
227+
if need_prompt? do
228+
buf = [:lists.duplicate(count, prompt)|buf]
229+
end
230+
231+
{ result, buf }
206232
end
207233

208234
defp io_request({ :setopts, _opts }, buf) do
@@ -274,37 +300,37 @@ defmodule ExUnit.CaptureIO do
274300
do_get_until(input, mod, fun, args)
275301
end
276302

277-
defp do_get_until([], mod, fun, args, continuation // [])
303+
defp do_get_until([], mod, fun, args, continuation // [], count // 0)
278304

279-
defp do_get_until([], mod, fun, args, continuation) do
305+
defp do_get_until([], mod, fun, args, continuation, count) do
280306
case apply(mod, fun, [continuation, :eof | args]) do
281307
{ :done, result, rest_chars } ->
282308
set_input(rest_chars)
283-
result
309+
{ result, count + 1 }
284310
{ :more, next_continuation } ->
285-
do_get_until([], mod, fun, args, next_continuation)
311+
do_get_until([], mod, fun, args, next_continuation, count + 1)
286312
end
287313
end
288314

289-
defp do_get_until(input, mod, fun, args, continuation) do
315+
defp do_get_until(input, mod, fun, args, continuation, count) do
290316
{ line, rest } = Enum.split_while(input, fn(char) -> char != ?\n end)
291317

292318
case rest do
293319
[] ->
294320
case apply(mod, fun, [continuation, line | args]) do
295321
{ :done, result, rest_chars } ->
296322
set_input(rest_chars)
297-
result
323+
{ result, count + 1 }
298324
{ :more, next_continuation } ->
299-
do_get_until([], mod, fun, args, next_continuation)
325+
do_get_until([], mod, fun, args, next_continuation, count + 1)
300326
end
301327
[_|t] ->
302328
case apply(mod, fun, [continuation, line ++ '\n' | args]) do
303329
{ :done, result, rest_chars } ->
304330
set_input(rest_chars ++ t)
305-
result
331+
{ result, count + 1 }
306332
{ :more, next_continuation } ->
307-
do_get_until(t, mod, fun, args, next_continuation)
333+
do_get_until(t, mod, fun, args, next_continuation, count + 1)
308334
end
309335
end
310336
end

lib/ex_unit/test/ex_unit/capture_io_test.exs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ defmodule ExUnit.CaptureIOTest do
7878
test :capture_io_with_get_chars do
7979
assert capture_io(fn ->
8080
:io.get_chars(">", 3)
81-
end) == nil
81+
end) == ">"
8282

8383
capture_io(fn ->
8484
assert :io.get_chars(">", 3) == :eof
@@ -104,7 +104,7 @@ defmodule ExUnit.CaptureIOTest do
104104
test :capture_io_with_get_line do
105105
assert capture_io(fn ->
106106
:io.get_line ">"
107-
end) == nil
107+
end) == ">"
108108

109109
capture_io(fn ->
110110
assert :io.get_line(">") == :eof
@@ -144,8 +144,16 @@ defmodule ExUnit.CaptureIOTest do
144144

145145
test :capture_io_with_get_until do
146146
assert capture_io(fn ->
147-
assert :io.scan_erl_form('>')
148-
end) == nil
147+
:io.scan_erl_form('>')
148+
end) == ">"
149+
150+
assert capture_io("1.\n", fn ->
151+
:io.scan_erl_form('>')
152+
end) == ">"
153+
154+
assert capture_io("1\n.\n", fn ->
155+
:io.scan_erl_form('>')
156+
end) == ">>"
149157

150158
capture_io(fn ->
151159
assert :io.scan_erl_form('>') == { :eof, 1 }

0 commit comments

Comments
 (0)