@@ -9,7 +9,7 @@ import scala.tools.partest._
9
9
import scala .tools .partest .nest ._
10
10
import scala .util .matching .Regex
11
11
import tools .nsc .io .{ File => NSCFile }
12
- import java .io .File
12
+ import java .io .{ File , PrintStream , FileOutputStream }
13
13
import java .net .URLClassLoader
14
14
15
15
/** Runs dotty partest from the Console, discovering test sources in
@@ -25,7 +25,7 @@ object DPConsoleRunner {
25
25
val (jarList, otherArgs) = args.toList.partition(jarFinder.findFirstIn(_).isDefined)
26
26
val (extraJars, moreArgs) = jarList match {
27
27
case Nil => sys.error(" Error: DPConsoleRunner needs \" -dottyJars <jarCount> <jars>*\" ." )
28
- case jarFinder(nr, jarString) :: Nil =>
28
+ case jarFinder(nr, jarString) :: Nil =>
29
29
val jars = jarString.split(" " ).toList
30
30
val count = nr.toInt
31
31
if (jars.length < count)
@@ -39,13 +39,13 @@ object DPConsoleRunner {
39
39
40
40
// console runner has a suite runner which creates a test runner for each test
41
41
class DPConsoleRunner (args : String , extraJars : List [String ]) extends ConsoleRunner (args) {
42
- println(" ConsoleRunner options: " + args)
43
42
44
43
override val suiteRunner = new DPSuiteRunner (
45
44
testSourcePath = optSourcePath getOrElse DPConfig .testRoot,
46
45
fileManager = new DottyFileManager (extraJars),
47
46
updateCheck = optUpdateCheck,
48
- failed = optFailed)
47
+ failed = optFailed,
48
+ consoleArgs = args)
49
49
50
50
override def run = {}
51
51
def runPartest = super .run
@@ -62,9 +62,10 @@ class DPSuiteRunner(testSourcePath: String, // relative path, like "files", or "
62
62
fileManager : DottyFileManager ,
63
63
updateCheck : Boolean ,
64
64
failed : Boolean ,
65
+ consoleArgs : String ,
65
66
javaCmdPath : String = PartestDefaults .javaCmd,
66
67
javacCmdPath : String = PartestDefaults .javacCmd,
67
- scalacExtraArgs : Seq [String ] = Seq .empty)
68
+ scalacExtraArgs : Seq [String ] = Seq .empty)
68
69
extends SuiteRunner (testSourcePath, fileManager, updateCheck, failed, javaCmdPath, javacCmdPath, scalacExtraArgs) {
69
70
70
71
if (! DPConfig .runTestsInParallel)
@@ -76,41 +77,52 @@ extends SuiteRunner(testSourcePath, fileManager, updateCheck, failed, javaCmdPat
76
77
override def banner : String = {
77
78
s """ |Welcome to Partest for Dotty! Partest version: ${Properties .versionNumberString}
78
79
|Compiler under test: dotty.tools.dotc.Bench or dotty.tools.dotc.Main
79
- |Test root : ${PathSettings .srcDir}${File .separator}
80
+ |Generated test sources : ${PathSettings .srcDir}${File .separator}
80
81
|Test directories: ${DPConfig .testDirs.toList.mkString(" , " )}
82
+ |Debugging: failed tests have compiler output in test-kind.clog, run output in test-kind.log, class files in test-kind.obj
81
83
|Parallel: ${DPConfig .runTestsInParallel}
84
+ |Options: (use partest --help for usage information) ${consoleArgs}
82
85
""" .stripMargin
83
86
}
84
87
85
- // override to provide DPTestRunner
88
+ // override for DPTestRunner and redirecting compilation output to test.clog
86
89
override def runTest (testFile : File ): TestState = {
87
90
val runner = new DPTestRunner (testFile, this )
88
91
89
- // when option "--failed" is provided execute test only if log
90
- // is present (which means it failed before)
91
92
val state =
92
- if (failed && ! runner.logFile.canRead)
93
- runner.genPass()
94
- else {
95
- val (state, _) =
96
- try timed(runner.run())
97
- catch {
98
- case t : Throwable => throw new RuntimeException (s " Error running $testFile" , t)
99
- }
100
- NestUI .reportTest(state)
101
- runner.cleanup()
102
- state
93
+ try {
94
+ // IO redirection is messy, there are no concurrency guarantees.
95
+ // Parts of test output might end up in the wrong file or get lost.
96
+ Console .out.flush
97
+ Console .err.flush
98
+ val clog = runner.cLogFile
99
+ val stream = new PrintStream (new FileOutputStream (clog.jfile), true )
100
+ val result = Console .withOut(stream)({ Console .withErr(stream)({
101
+ val res = runner.run()
102
+ Console .err.flush
103
+ Console .out.flush
104
+ res
105
+ })})
106
+ result match {
107
+ // Append compiler output to transcript if compilation failed,
108
+ // printed with --verbose option
109
+ case TestState .Fail (f, r@ " compilation failed" , transcript) =>
110
+ TestState .Fail (f, r, transcript ++ clog.fileLines.dropWhile(_ == " " ))
111
+ case res => res
112
+ }
113
+ } catch {
114
+ case t : Throwable => throw new RuntimeException (s " Error running $testFile" , t)
103
115
}
116
+ NestUI .reportTest(state)
117
+ runner.cleanup()
118
+
104
119
onFinishTest(testFile, state)
105
120
}
106
-
107
- // override val fileManager = new DottyFileManager(testClassLoader)
108
- // sbt package generates a dotty compiler jar, currently
109
- // ".../git/dotty/target/scala-2.11/dotty_2.11-0.1-SNAPSHOT.jar"
110
- // but it doesn't seem to be used anywhere
111
121
}
112
122
113
123
class DPTestRunner (testFile : File , suiteRunner : DPSuiteRunner ) extends nest.Runner (testFile, suiteRunner) {
124
+ val cLogFile = SFile (logFile).changeExtension(" clog" )
125
+
114
126
// override to provide DottyCompiler
115
127
override def newCompiler = new dotty.partest.DPDirectCompiler (this )
116
128
@@ -146,18 +158,18 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn
146
158
def nerrIsOk (reason : String ) = {
147
159
val nerrFinder = """ compilation failed with (\d+) errors""" .r
148
160
reason match {
149
- case nerrFinder(found) =>
161
+ case nerrFinder(found) =>
150
162
SFile (FileOps (testFile) changeExtension " nerr" ).safeSlurp match {
151
163
case Some (exp) if (exp != found) => CompFailedButWrongNErr (exp, found)
152
164
case _ => CompFailed
153
165
}
154
166
case _ => CompFailed
155
167
}
156
168
}
157
-
169
+
158
170
// we keep the partest semantics where only one round needs to fail
159
171
// compilation, not all
160
- val compFailingRounds = compilationRounds(testFile).map({round =>
172
+ val compFailingRounds = compilationRounds(testFile).map({round =>
161
173
val ok = round.isOk
162
174
setLastState(if (ok) genPass else genFail(" compilation failed" ))
163
175
(round.result, ok)
@@ -173,14 +185,14 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn
173
185
if (failureStates.exists({ case CompFailed => true ; case _ => false })) {
174
186
true
175
187
} else {
176
- val existsNerr = failureStates.exists({
188
+ val existsNerr = failureStates.exists({
177
189
case CompFailedButWrongNErr (exp, found) => nextTestActionFailing(s " wrong number of compilation errors, expected: $exp, found: $found" ); true
178
190
case _ => false
179
191
})
180
192
if (existsNerr) {
181
- false
193
+ false
182
194
} else {
183
- val existsDiff = failureStates.exists({
195
+ val existsDiff = failureStates.exists({
184
196
case CompFailedButWrongDiff () => nextTestActionFailing(s " output differs " ); true
185
197
case _ => false
186
198
})
@@ -193,6 +205,38 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn
193
205
}
194
206
}
195
207
208
+ // override to change check file updating to original file, not generated
209
+ override def diffIsOk : Boolean = {
210
+ // always normalize the log first
211
+ normalizeLog()
212
+ val diff = currentDiff
213
+ // if diff is not empty, is update needed?
214
+ val updating : Option [Boolean ] = (
215
+ if (diff == " " ) None
216
+ else Some (suiteRunner.updateCheck)
217
+ )
218
+ pushTranscript(s " diff $logFile $checkFile" )
219
+ nextTestAction(updating) {
220
+ case Some (true ) =>
221
+ val origCheck = SFile (checkFile.changeExtension(" checksrc" ).fileLines(1 ))
222
+ NestUI .echo(" Updating original checkfile " + origCheck)
223
+ origCheck writeAll file2String(logFile)
224
+ genUpdated()
225
+ case Some (false ) =>
226
+ // Get a word-highlighted diff from git if we can find it
227
+ val bestDiff = if (updating.isEmpty) " " else {
228
+ if (checkFile.canRead)
229
+ gitDiff(logFile, checkFile) getOrElse {
230
+ s " diff $logFile $checkFile\n $diff"
231
+ }
232
+ else diff
233
+ }
234
+ pushTranscript(bestDiff)
235
+ genFail(" output differs" )
236
+ case None => genPass() // redundant default case
237
+ } getOrElse true
238
+ }
239
+
196
240
// override because Dotty currently doesn't handle separate compilation well,
197
241
// so we ignore groups (tests suffixed with _1 and _2)
198
242
override def groupedFiles (sources : List [File ]): List [List [File ]] = {
@@ -217,4 +261,10 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn
217
261
// override to add dotty and scala jars to classpath
218
262
override def extraClasspath = suiteRunner.fileManager.asInstanceOf [DottyFileManager ].extraJarList ::: super .extraClasspath
219
263
264
+ // override to keep class files if failed and delete clog if ok
265
+ override def cleanup = if (lastState.isOk) {
266
+ logFile.delete
267
+ cLogFile.delete
268
+ Directory (outDir).deleteRecursively
269
+ }
220
270
}
0 commit comments