@@ -476,10 +476,16 @@ func _childProcess() {
476
476
let parts = line. _split ( separator: " ; " )
477
477
let testSuiteName = parts [ 0 ]
478
478
let testName = parts [ 1 ]
479
+ var testParameter : Int ?
480
+ if parts. count > 2 {
481
+ testParameter = Int ( parts [ 2 ] ) !
482
+ } else {
483
+ testParameter = nil
484
+ }
479
485
480
486
let testSuite = _allTestSuites [ _testSuiteNameToIndex [ testSuiteName] !]
481
487
_anyExpectFailed = false
482
- testSuite. _runTest ( testName)
488
+ testSuite. _runTest ( name : testName, parameter : testParameter )
483
489
484
490
print ( " \( _stdlibUnittestStreamPrefix) ;end; \( _anyExpectFailed) " )
485
491
@@ -530,15 +536,23 @@ struct _ParentProcess {
530
536
}
531
537
532
538
/// Returns the values of the corresponding variables in the child process.
533
- mutating func _runTestInChild( testSuite: TestSuite , _ testName: String )
534
- -> ( anyExpectFailed: Bool , seenExpectCrash: Bool ,
539
+ internal mutating func _runTestInChild(
540
+ testSuite: TestSuite ,
541
+ _ testName: String ,
542
+ parameter: Int ?
543
+ ) -> ( anyExpectFailed: Bool , seenExpectCrash: Bool ,
535
544
status: ProcessTerminationStatus ? ,
536
545
crashStdout: [ String ] , crashStderr: [ String ] ) {
537
546
if _pid <= 0 {
538
547
_spawnChild ( )
539
548
}
540
549
541
- print ( " \( testSuite. name) ; \( testName) " , to: & _childStdin)
550
+ print ( " \( testSuite. name) ; \( testName) " , terminator: " " , to: & _childStdin)
551
+ if let parameter = parameter {
552
+ print ( " ; " , terminator: " " , to: & _childStdin)
553
+ print ( parameter, terminator: " " , to: & _childStdin)
554
+ }
555
+ print ( " " , to: & _childStdin)
542
556
543
557
let currentTest = testSuite. _testByName ( testName)
544
558
if let stdinText = currentTest. stdinText {
@@ -667,6 +681,100 @@ struct _ParentProcess {
667
681
capturedCrashStdout, capturedCrashStderr)
668
682
}
669
683
684
+ internal enum _TestStatus {
685
+ case skip( [ TestRunPredicate ] )
686
+ case pass
687
+ case fail
688
+ case uxPass
689
+ case xFail
690
+ }
691
+
692
+ internal mutating func runOneTest(
693
+ fullTestName fullTestName: String ,
694
+ testSuite: TestSuite ,
695
+ test t: TestSuite . _Test ,
696
+ testParameter: Int ?
697
+ ) -> _TestStatus {
698
+ let activeSkips = t. getActiveSkipPredicates ( )
699
+ if !activeSkips. isEmpty {
700
+ return . skip( activeSkips)
701
+ }
702
+
703
+ let activeXFails = t. getActiveXFailPredicates ( )
704
+ let expectXFail = !activeXFails. isEmpty
705
+ let activeXFailsText = expectXFail ? " (XFAIL: \( activeXFails) ) " : " "
706
+ print ( " [ RUN ] \( fullTestName) \( activeXFailsText) " )
707
+
708
+ var expectCrash = false
709
+ var childTerminationStatus : ProcessTerminationStatus ? = nil
710
+ var crashStdout : [ String ] = [ ]
711
+ var crashStderr : [ String ] = [ ]
712
+ if _runTestsInProcess {
713
+ if t. stdinText != nil {
714
+ print ( " The test \( fullTestName) requires stdin input and can't be run in-process, marking as failed " )
715
+ _anyExpectFailed = true
716
+ } else {
717
+ _anyExpectFailed = false
718
+ testSuite. _runTest ( name: t. name, parameter: testParameter)
719
+ }
720
+ } else {
721
+ ( _anyExpectFailed, expectCrash, childTerminationStatus, crashStdout,
722
+ crashStderr) =
723
+ _runTestInChild ( testSuite, t. name, parameter: testParameter)
724
+ }
725
+
726
+ // Determine if the test passed, not taking XFAILs into account.
727
+ var testPassed = false
728
+ switch ( childTerminationStatus, expectCrash) {
729
+ case ( . none, false ) :
730
+ testPassed = !_anyExpectFailed
731
+
732
+ case ( . none, true ) :
733
+ testPassed = false
734
+ print ( " expecting a crash, but the test did not crash " )
735
+
736
+ case ( . some( _) , false ) :
737
+ testPassed = false
738
+ print ( " the test crashed unexpectedly " )
739
+
740
+ case ( . some( _) , true ) :
741
+ testPassed = !_anyExpectFailed
742
+ }
743
+ if testPassed && t. crashOutputMatches. count > 0 {
744
+ // If we still think that the test passed, check if the crash
745
+ // output matches our expectations.
746
+ let crashOutput = crashStdout + crashStderr
747
+ for expectedSubstring in t. crashOutputMatches {
748
+ var found = false
749
+ for s in crashOutput {
750
+ if findSubstring ( s, expectedSubstring) != nil {
751
+ found = true
752
+ break
753
+ }
754
+ }
755
+ if !found {
756
+ print ( " did not find expected string after crash: \( expectedSubstring. debugDescription) " )
757
+ testPassed = false
758
+ }
759
+ }
760
+ }
761
+
762
+ // Apply XFAILs.
763
+ switch ( testPassed, expectXFail) {
764
+ case ( true , false ) :
765
+ return . pass
766
+
767
+ case ( true , true ) :
768
+ return . uxPass
769
+
770
+ case ( false , false ) :
771
+ return . fail
772
+
773
+ case ( false , true ) :
774
+ return . xFail
775
+ }
776
+ }
777
+
670
778
mutating func run( ) {
671
779
if let filter = _filter {
672
780
print ( " StdlibUnittest: using filter: \( filter) " )
@@ -676,92 +784,43 @@ struct _ParentProcess {
676
784
var failedTests : [ String ] = [ ]
677
785
var skippedTests : [ String ] = [ ]
678
786
for t in testSuite. _tests {
679
- let fullTestName = " \( testSuite. name) . \( t. name) "
680
- if let filter = _filter where findSubstring ( fullTestName, filter) == nil {
681
- continue
682
- }
683
-
684
- let activeSkips = t. getActiveSkipPredicates ( )
685
- if !activeSkips. isEmpty {
686
- skippedTests. append ( t. name)
687
- print ( " [ SKIP ] \( fullTestName) (skip: \( activeSkips) ) " )
688
- continue
689
- }
690
-
691
- let activeXFails = t. getActiveXFailPredicates ( )
692
- let expectXFail = !activeXFails. isEmpty
693
- let activeXFailsText = expectXFail ? " (XFAIL: \( activeXFails) ) " : " "
694
- print ( " [ RUN ] \( fullTestName) \( activeXFailsText) " )
695
-
696
- var expectCrash = false
697
- var childTerminationStatus : ProcessTerminationStatus ? = nil
698
- var crashStdout : [ String ] = [ ]
699
- var crashStderr : [ String ] = [ ]
700
- if _runTestsInProcess {
701
- if t. stdinText != nil {
702
- print ( " The test \( fullTestName) requires stdin input and can't be run in-process, marking as failed " )
703
- _anyExpectFailed = true
704
- } else {
705
- _anyExpectFailed = false
706
- testSuite. _runTest ( t. name)
787
+ for testParameter in t. parameterValues {
788
+ var testName = t. name
789
+ if let testParameter = testParameter {
790
+ testName += " / "
791
+ testName += String ( testParameter)
707
792
}
708
- } else {
709
- ( _anyExpectFailed, expectCrash, childTerminationStatus, crashStdout,
710
- crashStderr) =
711
- _runTestInChild ( testSuite, t. name)
712
- }
793
+ var fullTestName = " \( testSuite. name) . \( testName) "
794
+ if let filter = _filter
795
+ where findSubstring ( fullTestName, filter) == nil {
713
796
714
- // Determine if the test passed, not taking XFAILs into account.
715
- var testPassed = false
716
- switch ( childTerminationStatus, expectCrash) {
717
- case ( . none, false ) :
718
- testPassed = !_anyExpectFailed
719
-
720
- case ( . none, true ) :
721
- testPassed = false
722
- print ( " expecting a crash, but the test did not crash " )
723
-
724
- case ( . some( _) , false ) :
725
- testPassed = false
726
- print ( " the test crashed unexpectedly " )
727
-
728
- case ( . some( _) , true ) :
729
- testPassed = !_anyExpectFailed
730
- }
731
- if testPassed && t. crashOutputMatches. count > 0 {
732
- // If we still think that the test passed, check if the crash
733
- // output matches our expectations.
734
- let crashOutput = crashStdout + crashStderr
735
- for expectedCrashOutput in t. crashOutputMatches {
736
- var found = false
737
- for s in crashOutput {
738
- if findSubstring ( s, expectedCrashOutput) != nil {
739
- found = true
740
- break
741
- }
742
- }
743
- if !found {
744
- print ( " did not find expected string after crash: \( expectedCrashOutput. debugDescription) " )
745
- testPassed = false
746
- }
797
+ continue
747
798
}
748
- }
749
-
750
- // Apply XFAILs.
751
- switch ( testPassed, expectXFail) {
752
- case ( true , false ) :
753
- print ( " [ OK ] \( fullTestName) " )
754
-
755
- case ( true , true ) :
756
- uxpassedTests. append ( t. name)
757
- print ( " [ UXPASS ] \( fullTestName) " )
758
799
759
- case ( false , false ) :
760
- failedTests. append ( t. name)
761
- print ( " [ FAIL ] \( fullTestName) " )
762
-
763
- case ( false , true ) :
764
- print ( " [ XFAIL ] \( fullTestName) " )
800
+ switch runOneTest (
801
+ fullTestName: fullTestName,
802
+ testSuite: testSuite,
803
+ test: t,
804
+ testParameter: testParameter
805
+ ) {
806
+ case . skip( let activeSkips) :
807
+ skippedTests. append ( testName)
808
+ print ( " [ SKIP ] \( fullTestName) (skip: \( activeSkips) ) " )
809
+
810
+ case . pass:
811
+ print ( " [ OK ] \( fullTestName) " )
812
+
813
+ case . uxPass:
814
+ uxpassedTests. append ( testName)
815
+ print ( " [ UXPASS ] \( fullTestName) " )
816
+
817
+ case . fail:
818
+ failedTests. append ( testName)
819
+ print ( " [ FAIL ] \( fullTestName) " )
820
+
821
+ case . xFail:
822
+ print ( " [ XFAIL ] \( fullTestName) " )
823
+ }
765
824
}
766
825
}
767
826
@@ -927,7 +986,7 @@ public class TestSuite {
927
986
_testTearDownCode = code
928
987
}
929
988
930
- func _runTest( testName: String ) {
989
+ func _runTest( name testName: String , parameter : Int ? ) {
931
990
PersistentState . ranSomething = true
932
991
for r in _allResettables {
933
992
r. reset ( )
@@ -937,7 +996,15 @@ public class TestSuite {
937
996
f ( )
938
997
}
939
998
let test = _testByName ( testName)
940
- test. code ( )
999
+ switch test. code {
1000
+ case . single( let code) :
1001
+ precondition (
1002
+ parameter == nil ,
1003
+ " can't pass parameters to parameterized tests " )
1004
+ code ( )
1005
+ case . parameterized( code: let code, _) :
1006
+ code ( parameter!)
1007
+ }
941
1008
if let f = _testTearDownCode {
942
1009
f ( )
943
1010
}
@@ -950,15 +1017,20 @@ public class TestSuite {
950
1017
return _tests [ _testNameToIndex [ testName] !]
951
1018
}
952
1019
953
- struct _Test {
1020
+ internal enum _TestCode {
1021
+ case single( code: ( ) -> Void )
1022
+ case parameterized( code: ( Int ) -> Void , count: Int )
1023
+ }
1024
+
1025
+ internal struct _Test {
954
1026
let name : String
955
1027
let testLoc : SourceLoc
956
1028
let xfail : [ TestRunPredicate ]
957
1029
let skip : [ TestRunPredicate ]
958
1030
let stdinText : String ?
959
1031
let stdinEndsWithEOF : Bool
960
1032
let crashOutputMatches : [ String ]
961
- let code : ( ) -> Void
1033
+ let code : _TestCode
962
1034
963
1035
/// Whether the test harness should stop reusing the child process after
964
1036
/// running this test.
@@ -973,6 +1045,15 @@ public class TestSuite {
973
1045
func getActiveSkipPredicates( ) -> [ TestRunPredicate ] {
974
1046
return skip. filter { $0. evaluate ( ) }
975
1047
}
1048
+
1049
+ var parameterValues : [ Int ? ] {
1050
+ switch code {
1051
+ case . single:
1052
+ return [ nil ]
1053
+ case . parameterized( code: _, count: let count) :
1054
+ return ( 0 ..< count) . map { $0 }
1055
+ }
1056
+ }
976
1057
}
977
1058
978
1059
public struct _TestBuilder {
@@ -1016,16 +1097,30 @@ public class TestSuite {
1016
1097
return self
1017
1098
}
1018
1099
1019
- public func code ( testFunction : ( ) -> Void ) {
1100
+ internal func _build ( testCode : _TestCode ) {
1020
1101
_testSuite. _tests. append (
1021
1102
_Test (
1022
1103
name: _name, testLoc: _data. _testLoc!, xfail: _data. _xfail,
1023
1104
skip: _data. _skip,
1024
1105
stdinText: _data. _stdinText,
1025
1106
stdinEndsWithEOF: _data. _stdinEndsWithEOF,
1026
- crashOutputMatches: _data. _crashOutputMatches, code: testFunction) )
1107
+ crashOutputMatches: _data. _crashOutputMatches,
1108
+ code: testCode) )
1027
1109
_testSuite. _testNameToIndex [ _name] = _testSuite. _tests. count - 1
1028
1110
}
1111
+
1112
+ public func code( testFunction: ( ) -> Void ) {
1113
+ _build ( . single( code: testFunction) )
1114
+ }
1115
+
1116
+ public func forEach< Data> (
1117
+ in parameterSets: [ Data ] ,
1118
+ testFunction: ( Data ) -> Void
1119
+ ) {
1120
+ _build ( . parameterized(
1121
+ code: { ( i: Int ) in testFunction ( parameterSets [ i] ) } ,
1122
+ count: parameterSets. count) )
1123
+ }
1029
1124
}
1030
1125
1031
1126
var name : String
0 commit comments