@@ -9,6 +9,7 @@ using Printf: @sprintf
99using Base. Filesystem: path_separator
1010import Test
1111import Random
12+ import IOCapture
1213
1314# Always set the max rss so that if tests add large global variables (which they do) we don't make the GC's life too hard
1415if Sys. WORD_SIZE == 64
8283#
8384
8485struct TestIOContext
85- io:: IO
86+ stdout :: IO
87+ stderr :: IO
8688 lock:: ReentrantLock
8789 name_align:: Int
8890 elapsed_align:: Int
@@ -92,28 +94,28 @@ struct TestIOContext
9294 rss_align:: Int
9395end
9496
95- function test_IOContext (:: Type{TestRecord} , io :: IO , lock:: ReentrantLock , name_align:: Int )
97+ function test_IOContext (:: Type{TestRecord} , stdout :: IO , stderr :: IO , lock:: ReentrantLock , name_align:: Int )
9698 elapsed_align = textwidth (" Time (s)" )
9799 gc_align = textwidth (" GC (s)" )
98100 percent_align = textwidth (" GC %" )
99101 alloc_align = textwidth (" Alloc (MB)" )
100102 rss_align = textwidth (" RSS (MB)" )
101103
102104 return TestIOContext (
103- io , lock, name_align, elapsed_align, gc_align, percent_align,
105+ stdout , stderr , lock, name_align, elapsed_align, gc_align, percent_align,
104106 alloc_align, rss_align
105107 )
106108end
107109
108110function print_header (:: Type{TestRecord} , ctx:: TestIOContext , testgroupheader, workerheader)
109111 lock (ctx. lock)
110112 try
111- printstyled (ctx. io , " " ^ (ctx. name_align + textwidth (testgroupheader) - 3 ), " | " )
112- printstyled (ctx. io , " | ---------------- CPU ---------------- |\n " , color = :white )
113- printstyled (ctx. io , testgroupheader, color = :white )
114- printstyled (ctx. io , lpad (workerheader, ctx. name_align - textwidth (testgroupheader) + 1 ), " | " , color = :white )
115- printstyled (ctx. io , " Time (s) | GC (s) | GC % | Alloc (MB) | RSS (MB) |\n " , color = :white )
116- flush (ctx. io )
113+ printstyled (ctx. stdout , " " ^ (ctx. name_align + textwidth (testgroupheader) - 3 ), " | " )
114+ printstyled (ctx. stdout , " | ---------------- CPU ---------------- |\n " , color = :white )
115+ printstyled (ctx. stdout , testgroupheader, color = :white )
116+ printstyled (ctx. stdout , lpad (workerheader, ctx. name_align - textwidth (testgroupheader) + 1 ), " | " , color = :white )
117+ printstyled (ctx. stdout , " Time (s) | GC (s) | GC % | Alloc (MB) | RSS (MB) |\n " , color = :white )
118+ flush (ctx. stdout )
117119 finally
118120 unlock (ctx. lock)
119121 end
@@ -122,12 +124,13 @@ end
122124function print_test_started (:: Type{TestRecord} , wrkr, test, ctx:: TestIOContext )
123125 lock (ctx. lock)
124126 try
125- printstyled (test, color = :white )
127+ printstyled (ctx . stdout , test, color = :white )
126128 printstyled (
129+ ctx. stdout ,
127130 lpad (" ($wrkr )" , ctx. name_align - textwidth (test) + 1 , " " ), " |" ,
128131 " " ^ ctx. elapsed_align, " started at $(now ()) \n " , color = :white
129132 )
130- flush (ctx. io )
133+ flush (ctx. stdout )
131134 finally
132135 unlock (ctx. lock)
133136 end
@@ -136,22 +139,22 @@ end
136139function print_test_finished (test, wrkr, record:: TestRecord , ctx:: TestIOContext )
137140 lock (ctx. lock)
138141 try
139- printstyled (ctx. io , test, color = :white )
140- printstyled (ctx. io , lpad (" ($wrkr )" , ctx. name_align - textwidth (test) + 1 , " " ), " | " , color = :white )
142+ printstyled (ctx. stdout , test, color = :white )
143+ printstyled (ctx. stdout , lpad (" ($wrkr )" , ctx. name_align - textwidth (test) + 1 , " " ), " | " , color = :white )
141144 time_str = @sprintf (" %7.2f" , record. time)
142- printstyled (ctx. io , lpad (time_str, ctx. elapsed_align, " " ), " | " , color = :white )
145+ printstyled (ctx. stdout , lpad (time_str, ctx. elapsed_align, " " ), " | " , color = :white )
143146
144147 gc_str = @sprintf (" %5.2f" , record. gctime)
145- printstyled (ctx. io , lpad (gc_str, ctx. gc_align, " " ), " | " , color = :white )
148+ printstyled (ctx. stdout , lpad (gc_str, ctx. gc_align, " " ), " | " , color = :white )
146149 percent_str = @sprintf (" %4.1f" , 100 * record. gctime / record. time)
147- printstyled (ctx. io , lpad (percent_str, ctx. percent_align, " " ), " | " , color = :white )
150+ printstyled (ctx. stdout , lpad (percent_str, ctx. percent_align, " " ), " | " , color = :white )
148151 alloc_str = @sprintf (" %5.2f" , record. bytes / 2 ^ 20 )
149- printstyled (ctx. io , lpad (alloc_str, ctx. alloc_align, " " ), " | " , color = :white )
152+ printstyled (ctx. stdout , lpad (alloc_str, ctx. alloc_align, " " ), " | " , color = :white )
150153
151154 rss_str = @sprintf (" %5.2f" , record. rss / 2 ^ 20 )
152- printstyled (ctx. io , lpad (rss_str, ctx. rss_align, " " ), " |\n " , color = :white )
155+ printstyled (ctx. stdout , lpad (rss_str, ctx. rss_align, " " ), " |\n " , color = :white )
153156
154- flush (ctx. io )
157+ flush (ctx. stdout )
155158 finally
156159 unlock (ctx. lock)
157160 end
@@ -160,13 +163,14 @@ end
160163function print_test_errorred (:: Type{TestRecord} , wrkr, test, ctx:: TestIOContext )
161164 lock (ctx. lock)
162165 try
163- printstyled (test, color = :red )
166+ printstyled (ctx . stderr , test, color = :red )
164167 printstyled (
168+ ctx. stderr ,
165169 lpad (" ($wrkr )" , ctx. name_align - textwidth (test) + 1 , " " ), " |" ,
166170 " " ^ ctx. elapsed_align, " failed at $(now ()) \n " , color = :red
167171 )
168172
169- flush (ctx. io )
173+ flush (ctx. stderr )
170174 finally
171175 unlock (ctx. lock)
172176 end
@@ -318,6 +322,7 @@ Several keyword arguments are also supported:
318322- `--quickfail`: Stop the entire test run as soon as any test fails
319323- `--jobs=N`: Use N worker processes (default: based on CPU threads and available memory)
320324- `TESTS...`: Filter tests by name, matched using `startswith`
325+ - `stdout` and `stderr`: I/O streams to write to (default: `Base.stdout` and `Base.stderr`)
321326
322327## Behavior
323328
@@ -352,7 +357,7 @@ issues during long test runs. The memory limit is set based on system architectu
352357"""
353358function runtests (ARGS ; testfilter = Returns (true ), RecordType = TestRecord,
354359 custom_tests:: Dict{String, Expr} = Dict {String, Expr} (), init_code = :(),
355- test_worker = Returns (nothing ))
360+ test_worker = Returns (nothing ), stdout = Base . stdout , stderr = Base . stderr )
356361 #
357362 # set-up
358363 #
@@ -453,7 +458,7 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
453458 if ! set_jobs
454459 jobs = default_njobs ()
455460 end
456- @info " Running $jobs tests in parallel. If this is too many, specify the `--jobs=N` argument to the tests, or set the `JULIA_CPU_THREADS` environment variable."
461+ println ( stdout , " Running $jobs tests in parallel. If this is too many, specify the `--jobs=N` argument to the tests, or set the `JULIA_CPU_THREADS` environment variable." )
457462
458463 # add workers
459464 addworkers (min (jobs, length (tests)))
@@ -490,7 +495,7 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
490495 while ! done
491496 c = read (term, Char)
492497 if c == ' \x 3'
493- println (" \n Caught interrupt, stopping..." )
498+ println (stderr , " \n Caught interrupt, stopping..." )
494499 stop_work ()
495500 break
496501 end
@@ -526,26 +531,26 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
526531 stderr . lock = print_lock
527532 end
528533
529- io_ctx = test_IOContext (RecordType, stdout , print_lock, name_align)
534+ io_ctx = test_IOContext (RecordType, stdout , stderr , print_lock, name_align)
530535 print_header (RecordType, io_ctx, testgroupheader, workerheader)
531536
532537 status_lines_visible = Ref (0 )
533538 function clear_status ()
534539 if status_lines_visible[] > 0
535540 for i in 1 : status_lines_visible[]
536- width = displaysize (stdout )[2 ]
537- print (stdout , " \r " , " " ^ width, " \r " )
541+ width = displaysize (io_ctx . stdout )[2 ]
542+ print (io_ctx . stdout , " \r " , " " ^ width, " \r " )
538543 if i < status_lines_visible[]
539- print (stdout , " \0 33[1A" ) # Move up
544+ print (io_ctx . stdout , " \0 33[1A" ) # Move up
540545 end
541546 end
542- print (stdout , " \r " )
547+ print (io_ctx . stdout , " \r " )
543548 status_lines_visible[] = 0
544549 end
545550 end
546551 function update_status ()
547552 # only draw the status bar on actual terminals
548- stdout isa Base. TTY || return
553+ io_ctx . stdout isa Base. TTY || return
549554
550555 # only draw if we have something to show
551556 isempty (running_tests) && return
@@ -562,7 +567,7 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
562567 end
563568 line2 = " Running: " * join (status_parts, " , " )
564569 # # truncate
565- max_width = displaysize (stdout )[2 ]
570+ max_width = displaysize (io_ctx . stdout )[2 ]
566571 if length (line2) > max_width
567572 line2 = line2[1 : max_width- 3 ] * " ..."
568573 end
@@ -580,10 +585,10 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
580585
581586 # display
582587 clear_status ()
583- println (stdout , line1)
584- println (stdout , line2)
585- print (stdout , line3)
586- flush (stdout )
588+ println (io_ctx . stdout , line1)
589+ println (io_ctx . stdout , line2)
590+ print (io_ctx . stdout , line3)
591+ flush (io_ctx . stdout )
587592 status_lines_visible[] = 3
588593 end
589594
@@ -721,7 +726,7 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
721726 try
722727 while true
723728 if any (istaskfailed, tasks)
724- println (" \n Caught an error, stopping..." )
729+ println (io_ctx . stderr , " \n Caught an error, stopping..." )
725730 break
726731 elseif done || (isempty (tests) && isempty (running_tests))
727732 break
@@ -784,19 +789,23 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
784789 fake
785790 elseif isa (resp, RemoteException) &&
786791 isa (resp. captured. ex, Test. TestSetException)
787- println (" Worker $(resp. pid) failed running test $(testname) :" )
788- Base. showerror (stdout , resp. captured)
789- println ()
792+ println (io_ctx. stderr , " Worker $(resp. pid) failed running test $(testname) :" )
793+ Base. showerror (io_ctx. stderr , resp. captured)
794+ println (io_ctx. stderr )
795+
790796 fake = Test. DefaultTestSet (testname)
791- for i in 1 : resp. captured. ex. pass
792- Test. record (fake, Test. Pass (:test , nothing , nothing , nothing , nothing ))
793- end
794- for i in 1 : resp. captured. ex. broken
795- Test. record (fake, Test. Broken (:test , nothing ))
796- end
797- for t in resp. captured. ex. errors_and_fails
798- Test. record (fake, t)
797+ c = IOCapture. capture () do
798+ for i in 1 : resp. captured. ex. pass
799+ Test. record (fake, Test. Pass (:test , nothing , nothing , nothing , nothing ))
800+ end
801+ for i in 1 : resp. captured. ex. broken
802+ Test. record (fake, Test. Broken (:test , nothing ))
803+ end
804+ for t in resp. captured. ex. errors_and_fails
805+ Test. record (fake, t)
806+ end
799807 end
808+ print (io_ctx. stdout , c. output)
800809 fake
801810 else
802811 if ! isa (resp, Exception)
@@ -807,7 +816,10 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
807816 # the test runner itself had some problem, so we may have hit a segfault,
808817 # deserialization errors or something similar. Record this testset as Errored.
809818 fake = Test. DefaultTestSet (testname)
810- Test. record (fake, Test. Error (:nontest_error , testname, nothing , Base. ExceptionStack ([(exception = resp, backtrace = [])]), LineNumberNode (1 )))
819+ c = IOCapture. capture () do
820+ Test. record (fake, Test. Error (:nontest_error , testname, nothing , Base. ExceptionStack ([(exception = resp, backtrace = [])]), LineNumberNode (1 )))
821+ end
822+ print (io_ctx. stdout , c. output)
811823 fake
812824 end
813825
@@ -828,20 +840,37 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
828840 for test in [tests; collect (keys (running_tests))]
829841 (test in completed_tests) && continue
830842 fake = Test. DefaultTestSet (test)
831- Test. record (fake, Test. Error (:test_interrupted , test, nothing , Base. ExceptionStack ([(exception = " skipped" , backtrace = [])]), LineNumberNode (1 )))
843+ c = IOCapture. capture () do
844+ Test. record (fake, Test. Error (:test_interrupted , test, nothing , Base. ExceptionStack ([(exception = " skipped" , backtrace = [])]), LineNumberNode (1 )))
845+ end
846+ print (io_ctx. stdout , c. output)
832847 with_testset (fake) do
833848 Test. record (o_ts, fake)
834849 end
835850 end
836851 end
837- println ()
838- Test. print_test_results (o_ts, 1 )
852+ println (io_ctx. stdout )
853+ if VERSION >= v " 1.13.0-DEV.1033"
854+ Test. print_test_results (io_ctx. stdout , o_ts, 1 )
855+ else
856+ c = IOCapture. capture () do
857+ Test. print_test_results (o_ts, 1 )
858+ end
859+ print (io_ctx. stdout , c. output)
860+ end
839861 if (VERSION >= v " 1.13.0-DEV.1037" && ! Test. anynonpass (o_ts)) ||
840862 (VERSION < v " 1.13.0-DEV.1037" && ! o_ts. anynonpass)
841- println (" \0 33[32;1mSUCCESS\0 33[0m" )
863+ println (io_ctx . stdout , " \0 33[32;1mSUCCESS\0 33[0m" )
842864 else
843- println (" \0 33[31;1mFAILURE\0 33[0m\n " )
844- Test. print_test_errors (o_ts)
865+ println (io_ctx. stderr , " \0 33[31;1mFAILURE\0 33[0m\n " )
866+ if VERSION >= v " 1.13.0-DEV.1033"
867+ Test. print_test_errors (io_ctx. stdout , o_ts)
868+ else
869+ c = IOCapture. capture () do
870+ Test. print_test_errors (o_ts)
871+ end
872+ print (io_ctx. stdout , c. output)
873+ end
845874 throw (Test. FallbackTestSetException (" Test run finished with errors" ))
846875 end
847876 return nothing
0 commit comments