6868abstract type  AbstractTestRecord end 
6969
7070struct  TestRecord <:  AbstractTestRecord 
71-     test:: Any 
72-     output:: String 
71+     value:: Any           #  AbstractTestSet or TestSetException
72+     output:: String       #  captured stdout/stderr
73+ 
74+     #  stats
7375    time:: Float64 
7476    bytes:: UInt64 
7577    gctime:: Float64 
@@ -165,7 +167,7 @@ function print_test_finished(record::TestRecord, wrkr, test, ctx::TestIOContext)
165167    end 
166168end 
167169
168- function  print_test_errorred ( :: Type{ TestRecord} :: TestIOContext , test_time )
170+ function  print_test_failed (record :: TestRecord , wrkr, test, ctx:: TestIOContext )
169171    lock (ctx. lock)
170172    try 
171173        printstyled (ctx. stderr , test, color =  :red )
@@ -174,7 +176,7 @@ function print_test_errorred(::Type{TestRecord}, wrkr, test, ctx::TestIOContext,
174176            lpad (" ($wrkr )" . name_align -  textwidth (test) +  1 , "  " "  |" 
175177            , color =  :red 
176178        )
177-         time_str =  @sprintf (" %7.2f" test_time )
179+         time_str =  @sprintf (" %7.2f" record . time )
178180        printstyled (ctx. stderr , lpad (time_str, ctx. elapsed_align +  1 , "  " "  │" =  :red )
179181
180182        failed_str =  " failed at $(now ()) \n " 
@@ -183,6 +185,24 @@ function print_test_errorred(::Type{TestRecord}, wrkr, test, ctx::TestIOContext,
183185        failed_str =  lpad (failed_str, fail_align, "  " 
184186        printstyled (ctx. stderr , failed_str, color =  :red )
185187
188+         #  TODO : print other stats?
189+ 
190+         flush (ctx. stderr )
191+     finally 
192+         unlock (ctx. lock)
193+     end 
194+ end 
195+ 
196+ function  print_test_crashed (:: Type{TestRecord} , wrkr, test, ctx:: TestIOContext )
197+     lock (ctx. lock)
198+     try 
199+         printstyled (ctx. stderr , test, color =  :red )
200+         printstyled (
201+             ctx. stderr ,
202+             lpad (" ($wrkr )" . name_align -  textwidth (test) +  1 , "  " "  |" 
203+             "  " ^ ctx. elapsed_align, "  crashed at $(now ()) \n " =  :red 
204+         )
205+ 
186206        flush (ctx. stderr )
187207    finally 
188208        unlock (ctx. lock)
@@ -209,8 +229,15 @@ function runtest(::Type{TestRecord}, f, name, init_code, color)
209229
210230            mktemp () do  path, io
211231                stats =  redirect_stdio (stdout = io, stderr = io) do 
212-                     @timed  @testset  $ name begin 
213-                         $ f
232+                     @timed  try 
233+                         @testset  $ name begin 
234+                             $ f
235+                         end 
236+                     catch  err
237+                         isa (err, Test. TestSetException) ||  rethrow ()
238+ 
239+                         #  return the error to package it into a TestRecord
240+                         err
214241                    end 
215242                end 
216243                close (io)
@@ -385,7 +412,7 @@ Run Julia tests in parallel across multiple worker processes.
385412
386413- `mod`: The module calling runtests 
387414- `ARGS`: Command line arguments array, typically from `Base.ARGS`. When you run the tests 
388-   with `Pkg.test `, this can be changed with the `test_args` keyword argument. 
415+   with `Pkg.value `, this can be changed with the `test_args` keyword argument. 
389416
390417Several keyword arguments are also supported: 
391418
@@ -665,7 +692,7 @@ function runtests(mod::Module, ARGS; test_filter = Returns(true), RecordType = T
665692    #  Message types for the printer channel
666693    #  (:started, test_name, worker_id)
667694    #  (:finished, test_name, worker_id, record)
668-     #  (:errored , test_name, worker_id, test_time)
695+     #  (:crashed , test_name, worker_id, test_time)
669696    printer_channel =  Channel {Tuple} (100 )
670697
671698    printer_task =  @async  begin 
@@ -692,13 +719,17 @@ function runtests(mod::Module, ARGS; test_filter = Returns(true), RecordType = T
692719                        test_name, wrkr, record =  msg[2 ], msg[3 ], msg[4 ]
693720
694721                        clear_status ()
695-                         print_test_finished (record, wrkr, test_name, io_ctx)
722+                         if  record. value isa  Exception
723+                             print_test_failed (record, wrkr, test_name, io_ctx)
724+                         else 
725+                             print_test_finished (record, wrkr, test_name, io_ctx)
726+                         end 
696727
697-                     elseif  msg_type ==  :errored  
698-                         test_name, wrkr, test_time  =  msg[2 ], msg[3 ], msg[ 4 ]
728+                     elseif  msg_type ==  :crashed  
729+                         test_name, wrkr  =  msg[2 ], msg[3 ]
699730
700731                        clear_status ()
701-                         print_test_errorred (RecordType, wrkr, test_name, io_ctx, test_time )
732+                         print_test_crashed (RecordType, wrkr, test_name, io_ctx)
702733                    end 
703734                end 
704735
@@ -766,16 +797,15 @@ function runtests(mod::Module, ARGS; test_filter = Returns(true), RecordType = T
766797                        break 
767798                    end 
768799
769-                     #  return any other exception as the result
770-                     #  XXX : also put this in a test record?
771800                    ex
772801                end 
773802                test_t1 =  time ()
774803                push! (results, (test, result, test_t0, test_t1))
775804
776805                #  act on the results
777806                if  result isa  AbstractTestRecord
778-                     put! (printer_channel, (:finished , test, wrkr, result:: RecordType ))
807+                     @assert  result isa  RecordType
808+                     put! (printer_channel, (:finished , test, wrkr, result))
779809
780810                    if  memory_usage (result) >  max_worker_rss
781811                        #  the worker has reached the max-rss limit, recycle it
@@ -784,13 +814,12 @@ function runtests(mod::Module, ARGS; test_filter = Returns(true), RecordType = T
784814                    end 
785815                else 
786816                    @assert  result isa  Exception
787-                     put! (printer_channel, (:errored  , test, wrkr, test_t1 - test_t0 ))
817+                     put! (printer_channel, (:crashed  , test, wrkr))
788818                    if  do_quickfail
789819                        stop_work ()
790820                    end 
791821
792-                     #  the worker encountered some failure, recycle it
793-                     #  so future tests get a fresh environment
822+                     #  the worker encountered some serious failure, recycle it
794823                    p =  recycle_worker (p)
795824                end 
796825
@@ -903,32 +932,33 @@ function runtests(mod::Module, ARGS; test_filter = Returns(true), RecordType = T
903932                push! (completed_tests, testname)
904933
905934                #  decode or fake a testset
906-                 if  isa (result, AbstractTestRecord)
907-                     testset =  result. test
908-                     historical_durations[testname] =  stop -  start
909-                 else 
910-                     testset =  create_testset (testname; start, stop)
911-                     if  isa (result, RemoteException) && 
912-                            isa (result. captured. ex, Test. TestSetException)
913-                         for  i in  1 : result. captured. ex. pass
935+                 if  result isa  AbstractTestRecord
936+                     if  result. value isa  Test. AbstractTestSet
937+                         testset =  result. value
938+                         historical_durations[testname] =  stop -  start
939+                     else 
940+                         #  TODO : improve the Test stdlib to keep track of the exact failure
941+                         #        instead of flattening into an exception without provenance
942+                         @assert  result. value isa  Test. TestSetException
943+                         testset =  create_testset (testname; start, stop)
944+                         for  i in  1 : result. value. pass
914945                            Test. record (testset, Test. Pass (:test , nothing , nothing , nothing , LineNumberNode (@__LINE__ , @__FILE__ )))
915946                        end 
916-                         for  i in  1 : result. captured . ex . broken
947+                         for  i in  1 : result. value . broken
917948                            Test. record (testset, Test. Broken (:test , nothing ))
918949                        end 
919-                         for  t in  result. captured . ex . errors_and_fails
950+                         for  t in  result. value . errors_and_fails
920951                            Test. record (testset, t)
921952                        end 
922-                     else 
923-                         if  ! isa (result, Exception)
924-                             result =  ErrorException (string (" Unknown result type : " typeof (result)))
925-                         end 
926-                         #  If this test raised an exception that is not a remote testset exception,
927-                         #  i.e. not a RemoteException capturing a TestSetException that means
928-                         #  the test runner itself had some problem, so we may have hit a segfault,
929-                         #  deserialization errors or something similar.  Record this testset as Errored.
930-                         Test. record (testset, Test. Error (:nontest_error , testname, nothing , Base. ExceptionStack (NamedTuple[(;exception =  result, backtrace =  [])]), LineNumberNode (1 )))
931953                    end 
954+                 else 
955+                     #  If this test raised an exception that is not a remote testset
956+                     #  exception, that means the test runner itself had some problem, so we
957+                     #  may have hit a segfault, deserialization errors or something similar.
958+                     #  Record this testset as Errored.
959+                     @assert  result isa  Exception
960+                     testset =  create_testset (testname; start, stop)
961+                     Test. record (testset, Test. Error (:nontest_error , testname, nothing , Base. ExceptionStack (NamedTuple[(;exception =  result, backtrace =  [])]), LineNumberNode (1 )))
932962                end 
933963
934964                with_testset (testset) do 
0 commit comments