@@ -166,30 +166,43 @@ private static string GenerateFullTestRunner(ImmutableArray<ITestInfo> testInfos
166166 CodeBuilder builder = new ( ) ;
167167 AppendAliasMap ( builder , aliasMap ) ;
168168
169- builder . AppendLine ( "System.Collections.Generic.HashSet<string> testExclusionList = XUnitWrapperLibrary.TestFilter.LoadTestExclusionList();" ) ;
169+ builder . AppendLine ( "XUnitWrapperLibrary.TestFilter filter;" ) ;
170+ builder . AppendLine ( "XUnitWrapperLibrary.TestSummary summary;" ) ;
171+ builder . AppendLine ( "System.Diagnostics.Stopwatch stopwatch;" ) ;
172+ builder . AppendLine ( "XUnitWrapperLibrary.TestOutputRecorder outputRecorder;" ) ;
170173 builder . AppendLine ( ) ;
171174
172- builder . AppendLine ( $@ "if (System.IO.File.Exists("" { assemblyName } .tempLog.xml"") )") ;
175+ builder . AppendLine ( "void Initialize( )") ;
173176 using ( builder . NewBracesScope ( ) )
174177 {
175- builder . AppendLine ( $@ "System.IO.File.Delete(""{ assemblyName } .tempLog.xml"");") ;
176- }
177- builder . AppendLine ( $@ "if (System.IO.File.Exists(""{ assemblyName } .testStats.csv""))") ;
178- using ( builder . NewBracesScope ( ) )
179- {
180- builder . AppendLine ( $@ "System.IO.File.Delete(""{ assemblyName } .testStats.csv"");") ;
178+ builder . AppendLine ( "System.Collections.Generic.HashSet<string> testExclusionList = XUnitWrapperLibrary.TestFilter.LoadTestExclusionList();" ) ;
179+ builder . AppendLine ( ) ;
180+
181+ builder . AppendLine ( $@ "if (System.IO.File.Exists(""{ assemblyName } .tempLog.xml""))") ;
182+ using ( builder . NewBracesScope ( ) )
183+ {
184+ builder . AppendLine ( $@ "System.IO.File.Delete(""{ assemblyName } .tempLog.xml"");") ;
185+ }
186+ builder . AppendLine ( $@ "if (System.IO.File.Exists(""{ assemblyName } .testStats.csv""))") ;
187+ using ( builder . NewBracesScope ( ) )
188+ {
189+ builder . AppendLine ( $@ "System.IO.File.Delete(""{ assemblyName } .testStats.csv"");") ;
190+ }
191+ builder . AppendLine ( ) ;
192+
193+ builder . AppendLine ( "filter = new (args, testExclusionList);" ) ;
194+ builder . AppendLine ( "summary = new();" ) ;
195+ builder . AppendLine ( "stopwatch = System.Diagnostics.Stopwatch.StartNew();" ) ;
196+ builder . AppendLine ( "outputRecorder = new(System.Console.Out);" ) ;
197+ builder . AppendLine ( "System.Console.SetOut(outputRecorder);" ) ;
181198 }
182199 builder . AppendLine ( ) ;
183200
184- builder . AppendLine ( "XUnitWrapperLibrary.TestFilter filter = new (args, testExclusionList);" ) ;
185- builder . AppendLine ( "XUnitWrapperLibrary.TestSummary summary = new();" ) ;
186- builder . AppendLine ( "System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();" ) ;
187- builder . AppendLine ( "XUnitWrapperLibrary.TestOutputRecorder outputRecorder = new(System.Console.Out);" ) ;
188- builder . AppendLine ( "System.Console.SetOut(outputRecorder);" ) ;
189- builder . AppendLine ( ) ;
201+ builder . AppendLine ( "Initialize();" ) ;
190202
203+ // Open the stream writer for the temp log.
191204 builder . AppendLine ( $@ "using (System.IO.StreamWriter tempLogSw = System.IO.File.AppendText(""{ assemblyName } .tempLog.xml""))") ;
192- builder . AppendLine ( $@ "using (System.IO.StreamWriter statsCsvSw = System.IO.File.AppendText(""{ assemblyName } .testStats.csv"")){{ ") ;
205+ builder . AppendLine ( $@ "using (System.IO.StreamWriter statsCsvSw = System.IO.File.AppendText(""{ assemblyName } .testStats.csv""))") ;
193206 CodeBuilder testExecutorBuilder = new ( ) ;
194207 int totalTestsEmitted = 0 ;
195208
@@ -209,9 +222,14 @@ private static string GenerateFullTestRunner(ImmutableArray<ITestInfo> testInfos
209222
210223 if ( testInfos . Length > 0 )
211224 {
212- // Break tests into groups of 50 so that we don't create an unreasonably large main method
213- // Excessively large methods are known to take a long time to compile, and use excessive stack
214- // leading to test failures.
225+ // This code breaks the tests into groups called by helper methods.
226+ //
227+ // Reasonably large methods are known to take a long time to compile, and use excessive stack
228+ // leading to test failures. Groups of 50 were sufficient to avoid this problem.
229+ //
230+ // However, large methods also appear to causes problems when the tests are run in gcstress
231+ // modes. Groups of 1 appear to help with this. It hasn't been directly measured but
232+ // experimentally has improved gcstress testing.
215233 foreach ( ITestInfo test in testInfos )
216234 {
217235 if ( testsLeftInCurrentTestExecutor == 0 )
@@ -224,12 +242,14 @@ private static string GenerateFullTestRunner(ImmutableArray<ITestInfo> testInfos
224242 }
225243
226244 currentTestExecutor ++ ;
227- testExecutorBuilder . AppendLine ( $ "void TestExecutor{ currentTestExecutor } (System.IO.StreamWriter tempLogSw, System.IO.StreamWriter statsCsvSw)") ;
245+ testExecutorBuilder . AppendLine ( $ "void TestExecutor{ currentTestExecutor } ("
246+ + "System.IO.StreamWriter tempLogSw, "
247+ + "System.IO.StreamWriter statsCsvSw)" ) ;
228248 testExecutorBuilder . AppendLine ( "{" ) ;
229249 testExecutorBuilder . PushIndent ( ) ;
230250
231251 builder . AppendLine ( $ "TestExecutor{ currentTestExecutor } (tempLogSw, statsCsvSw);") ;
232- testsLeftInCurrentTestExecutor = 50 ; // Break test executors into groups of 50 , which empirically seems to work well
252+ testsLeftInCurrentTestExecutor = 1 ; // Break test executors into groups of 1 , which empirically seems to work well
233253 }
234254 else
235255 {
@@ -246,21 +266,27 @@ private static string GenerateFullTestRunner(ImmutableArray<ITestInfo> testInfos
246266 testExecutorBuilder . AppendLine ( ) ;
247267 }
248268
249- testExecutorBuilder . AppendLine ( "}" ) ;
250- builder . AppendLine ( "tempLogSw.WriteLine(\" </assembly>\" );" ) ;
269+ builder . AppendLine ( "summary.WriteFooterToTempLog(tempLogSw);" ) ;
251270 }
252271 builder . AppendLine ( ) ;
253272
254- builder . AppendLine ( $@ "string testResults = summary.GetTestResultOutput(""{ assemblyName } "");") ;
255- builder . AppendLine ( $@ "string workitemUploadRoot = System.Environment.GetEnvironmentVariable(""HELIX_WORKITEM_UPLOAD_ROOT"");") ;
256- builder . AppendLine ( $@ "if (workitemUploadRoot != null)") ;
273+ builder . AppendLine ( "void Finish()" ) ;
257274 using ( builder . NewBracesScope ( ) )
258275 {
259- builder . AppendLine ( $@ "System.IO.File.WriteAllText(System.IO.Path.Combine(workitemUploadRoot, ""{ assemblyName } .testResults.xml.txt""), testResults);") ;
276+ builder . AppendLine ( $@ "string testResults = summary.GetTestResultOutput(""{ assemblyName } "");") ;
277+ builder . AppendLine ( $@ "string workitemUploadRoot = System.Environment.GetEnvironmentVariable(""HELIX_WORKITEM_UPLOAD_ROOT"");") ;
278+ builder . AppendLine ( $@ "if (workitemUploadRoot != null)") ;
279+ using ( builder . NewBracesScope ( ) )
280+ {
281+ builder . AppendLine ( $@ "System.IO.File.WriteAllText(System.IO.Path.Combine(workitemUploadRoot, ""{ assemblyName } .testResults.xml.txt""), testResults);") ;
282+ }
283+ builder . AppendLine ( ) ;
284+
285+ builder . AppendLine ( $@ "System.IO.File.WriteAllText(""{ assemblyName } .testResults.xml"", testResults);") ;
260286 }
261- builder . AppendLine ( ) ;
262287
263- builder . AppendLine ( $@ "System.IO.File.WriteAllText(""{ assemblyName } .testResults.xml"", testResults);") ;
288+ builder . AppendLine ( ) ;
289+ builder . AppendLine ( "Finish();" ) ;
264290 builder . AppendLine ( "return 100;" ) ;
265291 builder . AppendLine ( ) ;
266292
@@ -275,12 +301,15 @@ private static string GenerateXHarnessTestRunner(ImmutableArray<ITestInfo> testI
275301 CodeBuilder builder = new ( ) ;
276302 AppendAliasMap ( builder , aliasMap ) ;
277303
278- builder . AppendLine ( "System.Collections.Generic.HashSet<string> testExclusionList = XUnitWrapperLibrary.TestFilter.LoadTestExclusionList();" ) ;
304+ builder . AppendLine ( "XUnitWrapperLibrary.TestSummary summary;" ) ;
305+ builder . AppendLine ( "System.Diagnostics.Stopwatch stopwatch;" ) ;
306+ builder . AppendLine ( "XUnitWrapperLibrary.TestOutputRecorder outputRecorder;" ) ;
279307 builder . AppendLine ( ) ;
280308
281309 builder . AppendLine ( "try" ) ;
282310 using ( builder . NewBracesScope ( ) )
283311 {
312+ builder . AppendLine ( "System.Collections.Generic.HashSet<string> testExclusionList = XUnitWrapperLibrary.TestFilter.LoadTestExclusionList();" ) ;
284313 builder . AppendLine ( $@ "return await XHarnessRunnerLibrary.RunnerEntryPoint.RunTests(RunTests, ""{ assemblyName } "", args.Length != 0 ? args[0] : null, testExclusionList);") ;
285314 }
286315 builder . AppendLine ( "catch(System.Exception ex)" ) ;
@@ -291,15 +320,9 @@ private static string GenerateXHarnessTestRunner(ImmutableArray<ITestInfo> testI
291320 }
292321 builder . AppendLine ( ) ;
293322
294- builder . AppendLine ( "static XUnitWrapperLibrary.TestSummary RunTests(XUnitWrapperLibrary.TestFilter filter )" ) ;
323+ builder . AppendLine ( "void Initialize( )" ) ;
295324 using ( builder . NewBracesScope ( ) )
296325 {
297- builder . AppendLine ( "XUnitWrapperLibrary.TestSummary summary = new();" ) ;
298- builder . AppendLine ( "System.Diagnostics.Stopwatch stopwatch = new();" ) ;
299- builder . AppendLine ( "XUnitWrapperLibrary.TestOutputRecorder outputRecorder = new(System.Console.Out);" ) ;
300- builder . AppendLine ( "System.Console.SetOut(outputRecorder);" ) ;
301- builder . AppendLine ( ) ;
302-
303326 builder . AppendLine ( $@ "if (System.IO.File.Exists(""{ assemblyName } .tempLog.xml""))") ;
304327 using ( builder . NewBracesScope ( ) )
305328 {
@@ -312,24 +335,43 @@ private static string GenerateXHarnessTestRunner(ImmutableArray<ITestInfo> testI
312335 }
313336 builder . AppendLine ( ) ;
314337
315- ITestReporterWrapper reporter = new WrapperLibraryTestSummaryReporting ( "summary" , "filter" , "outputRecorder" ) ;
338+ builder . AppendLine ( "summary = new();" ) ;
339+ builder . AppendLine ( "stopwatch = new();" ) ;
340+ builder . AppendLine ( "outputRecorder = new(System.Console.Out);" ) ;
341+ builder . AppendLine ( "System.Console.SetOut(outputRecorder);" ) ;
342+ }
343+ builder . AppendLine ( ) ;
316344
317- CodeBuilder testExecutorBuilder = new ( ) ;
318- int testsLeftInCurrentTestExecutor = 0 ;
319- int currentTestExecutor = 0 ;
345+ builder . AppendLine ( "XUnitWrapperLibrary.TestSummary RunTests(XUnitWrapperLibrary.TestFilter filter)" ) ;
346+ using ( builder . NewBracesScope ( ) )
347+ {
348+ builder . AppendLine ( "Initialize();" ) ;
320349
321350 // Open the stream writer for the temp log.
322351 builder . AppendLine ( $@ "using (System.IO.StreamWriter tempLogSw = System.IO.File.AppendText(""{ assemblyName } .templog.xml""))") ;
323352 builder . AppendLine ( $@ "using (System.IO.StreamWriter statsCsvSw = System.IO.File.AppendText(""{ assemblyName } .testStats.csv""))") ;
353+ CodeBuilder testExecutorBuilder = new ( ) ;
354+
324355 using ( builder . NewBracesScope ( ) )
325356 {
326357 builder . AppendLine ( $ "statsCsvSw.WriteLine(\" { testInfos . Length } ,0,0,0\" );") ;
327358
359+ ITestReporterWrapper reporter =
360+ new WrapperLibraryTestSummaryReporting ( "summary" , "filter" , "outputRecorder" ) ;
361+
362+ int testsLeftInCurrentTestExecutor = 0 ;
363+ int currentTestExecutor = 0 ;
364+
328365 if ( testInfos . Length > 0 )
329366 {
330- // Break tests into groups of 50 so that we don't create an unreasonably large main method
331- // Excessively large methods are known to take a long time to compile, and use excessive stack
332- // leading to test failures.
367+ // This code breaks the tests into groups called by helper methods.
368+ //
369+ // Reasonably large methods are known to take a long time to compile, and use excessive stack
370+ // leading to test failures. Groups of 50 were sufficient to avoid this problem.
371+ //
372+ // However, large methods also appear to causes problems when the tests are run in gcstress
373+ // modes. Groups of 1 appear to help with this. It hasn't been directly measured but
374+ // experimentally has improved gcstress testing.
333375 foreach ( ITestInfo test in testInfos )
334376 {
335377 if ( testsLeftInCurrentTestExecutor == 0 )
@@ -342,18 +384,15 @@ private static string GenerateXHarnessTestRunner(ImmutableArray<ITestInfo> testI
342384 }
343385
344386 currentTestExecutor ++ ;
345- testExecutorBuilder . AppendLine ( $ "static void TestExecutor{ currentTestExecutor } ("
346- + "XUnitWrapperLibrary.TestSummary summary, "
387+ testExecutorBuilder . AppendLine ( $ "void TestExecutor{ currentTestExecutor } ("
347388 + "XUnitWrapperLibrary.TestFilter filter, "
348- + "XUnitWrapperLibrary.TestOutputRecorder outputRecorder, "
349- + "System.Diagnostics.Stopwatch stopwatch, "
350389 + "System.IO.StreamWriter tempLogSw, "
351390 + "System.IO.StreamWriter statsCsvSw)" ) ;
352391 testExecutorBuilder . AppendLine ( "{" ) ;
353392 testExecutorBuilder . PushIndent ( ) ;
354393
355- builder . AppendLine ( $ "TestExecutor{ currentTestExecutor } (summary, filter, outputRecorder, stopwatch , tempLogSw, statsCsvSw);") ;
356- testsLeftInCurrentTestExecutor = 50 ; // Break test executors into groups of 50 , which empirically seems to work well
394+ builder . AppendLine ( $ "TestExecutor{ currentTestExecutor } (filter, tempLogSw, statsCsvSw);") ;
395+ testsLeftInCurrentTestExecutor = 1 ; // Break test executors into groups of 1 , which empirically seems to work well
357396 }
358397 else
359398 {
0 commit comments