Merge lp:~charlie.poole/nunit-vs-adapter/rc1 into lp:nunit-vs-adapter

Proposed by Charlie Poole
Status: Merged
Merged at revision: 70
Proposed branch: lp:~charlie.poole/nunit-vs-adapter/rc1
Merge into: lp:nunit-vs-adapter
Diff against target: 1607 lines (+518/-556)
17 files modified
src/NUnitTestAdapter/AssemblyRunner.cs (+159/-77)
src/NUnitTestAdapter/NUnitEventListener.cs (+8/-34)
src/NUnitTestAdapter/NUnitTestAdapter.cs (+14/-78)
src/NUnitTestAdapter/NUnitTestAdapter.csproj (+5/-4)
src/NUnitTestAdapter/NUnitTestDiscoverer.cs (+13/-17)
src/NUnitTestAdapter/NUnitTestExecutor.cs (+25/-84)
src/NUnitTestAdapter/NavigationData.cs (+0/-131)
src/NUnitTestAdapter/TFSTestFilter.cs (+6/-2)
src/NUnitTestAdapter/TestConverter.cs (+120/-19)
src/NUnitTestAdapter/TestLogger.cs (+81/-0)
src/NUnitTestAdapter/TfsAssemblyFilter.cs (+0/-32)
src/NUnitTestAdapter/TraitsFeature.cs (+5/-1)
src/NUnitTestAdapterTests/AssemblyRunnerTests.cs (+24/-38)
src/NUnitTestAdapterTests/NUnitEventListenerTests.cs (+6/-4)
src/NUnitTestAdapterTests/NUnitTestAdapterTests.csproj (+1/-1)
src/NUnitTestAdapterTests/NavigationDataTests.cs (+8/-12)
src/NUnitTestAdapterTests/TestConverterTests.cs (+43/-22)
To merge this branch: bzr merge lp:~charlie.poole/nunit-vs-adapter/rc1
Reviewer Review Type Date Requested Status
NUnit Visual Studio Integration Team Pending
Review via email: mp+180266@code.launchpad.net

Description of the change

I made AssemblyRunner responsible for executing tests on a single assembly. This seems like a good division of responsibility, since it puts all the info that varies from one assembly to another into the same class. At the same time, I simplified the original caching logic. We no longer need or use the map of nunit test cases - only the map of VS test cases. Various other minor cleanups were made.

Please check that this runs correctly under TFS, as I'm not set up for this.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'src/NUnitTestAdapter/AssemblyFilter.cs' => 'src/NUnitTestAdapter/AssemblyRunner.cs'
2--- src/NUnitTestAdapter/AssemblyFilter.cs 2013-08-12 23:47:42 +0000
3+++ src/NUnitTestAdapter/AssemblyRunner.cs 2013-08-14 22:47:33 +0000
4@@ -1,95 +1,179 @@
5-namespace NUnit.VisualStudio.TestAdapter
6+// ****************************************************************
7+// Copyright (c) 2013 NUnit Software. All rights reserved.
8+// ****************************************************************
9+
10+namespace NUnit.VisualStudio.TestAdapter
11 {
12 using System;
13 using System.Collections.Generic;
14
15 using Microsoft.VisualStudio.TestPlatform.ObjectModel;
16+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
17
18 using NUnit.Core;
19 using NUnit.Core.Filters;
20+ using NUnit.Util;
21
22 /// <summary>
23- /// This class containts the filters and maps necessary for filtering of test cases for a given assembly
24+ /// The AssemblyRunner class executes tests in a single assembly
25 /// </summary>
26- public class AssemblyFilter : IDisposable
27+ public class AssemblyRunner : IDisposable
28 {
29- public TestFilter NUnitFilter { get; protected set; }
30-
31- public IList<TestCase> VsTestCases
32- {
33- get
34- {
35- return this.vsTestCases;
36- }
37- }
38-
39- public Dictionary<string, ITest> NUnitTestCaseMap
40- {
41- get
42- {
43- return this.nunitTestCaseMap;
44- }
45- }
46-
47- public string AssemblyName { get; private set; }
48-
49- // List of test cases used during execution
50- private readonly List<TestCase> vsTestCases;
51-
52- // Map of names to NUnit Test cases
53- private readonly Dictionary<string, ITest> nunitTestCaseMap;
54-
55+ private TestRunner runner = new TestDomain();
56+ private TestLogger logger;
57+ private string assemblyName;
58+
59+ private TestFilter nunitFilter;
60+ private List<TestCase> loadedTestCases;
61 private TestConverter testConverter;
62
63+ #region Constructors
64+
65+ // This constructor is called by the others and is used directly for testing
66+ public AssemblyRunner(TestLogger logger, string assemblyName)
67+ {
68+ this.logger = logger;
69+ this.assemblyName = assemblyName;
70+ this.testConverter = new TestConverter(logger, assemblyName);
71+ this.loadedTestCases = new List<TestCase>();
72+ this.nunitFilter = TestFilter.Empty;
73+ }
74+
75+ // This constructor is used when the executor is called with a list of test cases
76+ public AssemblyRunner(TestLogger logger, string assemblyName, IEnumerable<TestCase> selectedTestCases)
77+ : this(logger, assemblyName)
78+ {
79+ this.nunitFilter = MakeTestFilter(selectedTestCases);
80+ }
81+
82+ // This constructor is used when the executor is called with a list of assemblies
83+ public AssemblyRunner(TestLogger logger, string assemblyName, IRunContext runContext)
84+ : this(logger, assemblyName)
85+ {
86+ TFSTestFilter tfsFilter = new TFSTestFilter(runContext);
87+ if (tfsFilter.HasTfsFilterValue)
88+ {
89+ var filteredTestCases = tfsFilter.CheckFilter(this.LoadedTestCases);
90+ this.nunitFilter = MakeTestFilter(filteredTestCases);
91+ }
92+ }
93+
94+ private static SimpleNameFilter MakeTestFilter(IEnumerable<TestCase> ptestCases)
95+ {
96+ var filter = new SimpleNameFilter();
97+ foreach (TestCase testCase in ptestCases)
98+ {
99+ filter.Add(testCase.FullyQualifiedName);
100+ }
101+ return filter;
102+ }
103+
104+ #endregion
105+
106+ #region Properties
107+
108+ // TODO: Revise tests and remove
109+ public TestFilter NUnitFilter
110+ {
111+ get { return nunitFilter; }
112+ }
113+
114+ // TODO: Revise tests and remove
115+ public IList<TestCase> LoadedTestCases
116+ {
117+ get { return loadedTestCases; }
118+ }
119+
120+ // TODO: Revise tests and remove
121 public TestConverter TestConverter
122- {
123- get
124- {
125- return this.testConverter ?? (this.testConverter = new TestConverter(this.AssemblyName));
126- }
127- }
128-
129- public AssemblyFilter(string assemblyName)
130- {
131- this.AssemblyName = assemblyName;
132- this.NUnitFilter = TestFilter.Empty;
133- this.vsTestCases = new List<TestCase>();
134- this.nunitTestCaseMap = new Dictionary<string, ITest>();
135- }
136-
137- public AssemblyFilter(string assemblyName, TestFilter filter)
138- : this(assemblyName)
139- {
140- this.NUnitFilter = filter;
141- }
142-
143+ {
144+ get { return testConverter; }
145+ }
146+
147+ #endregion
148+
149+ #region Public Methods
150+
151+ public void RunAssembly(IFrameworkHandle testLog)
152+ {
153+ try
154+ {
155+#if LAUNCHDEBUGGER
156+ Debugger.Launch();
157+#endif
158+ if (TryLoadAssembly())
159+ {
160+ var listener = new NUnitEventListener(testLog, this.TestConverter);
161+
162+ try
163+ {
164+ runner.Run(listener, NUnitFilter, true, LoggingThreshold.Off);
165+ }
166+ catch (NullReferenceException)
167+ {
168+ // this happens during the run when CancelRun is called.
169+ logger.SendDebugMessage("Nullref caught");
170+ }
171+ finally
172+ {
173+ runner.Unload();
174+ }
175+ }
176+ else
177+ {
178+ logger.NUnitLoadError(assemblyName);
179+ }
180+ }
181+ catch (System.BadImageFormatException)
182+ {
183+ // we skip the native c++ binaries that we don't support.
184+ logger.AssemblyNotSupportedWarning(assemblyName);
185+ }
186+ catch (System.IO.FileNotFoundException ex)
187+ {
188+ // Probably from the GetExportedTypes in NUnit.core, attempting to find an assembly, not a problem if it is not NUnit here
189+ logger.DependentAssemblyNotFoundWarning(ex.FileName, assemblyName);
190+ }
191+ catch (Exception ex)
192+ {
193+ logger.SendErrorMessage("Exception thrown executing tests in " + assemblyName, ex);
194+ }
195+ }
196+
197+ public void CancelRun()
198+ {
199+ if (this.runner != null && this.runner.Running)
200+ this.runner.CancelRun();
201+ }
202+
203+ // Try to load the assembly and, if successful, populate
204+ // the list of all loaded assemblies. As a side effect
205+ // of calling TestConverter.ConvertTestCase, the converter's
206+ // cache of all test cases is populated as well. All
207+ // future calls to convert a test case may now use the cache.
208+ private bool TryLoadAssembly()
209+ {
210+ var package = new TestPackage(assemblyName);
211+
212+ if (!runner.Load(package))
213+ return false;
214+
215+ AddTestCases(runner.Test);
216+
217+ return true;
218+ }
219+
220+ // This method is public for testing purposes.
221+ // TODO: Test by actually loading an assembly and make it private
222 public void AddTestCases(ITest test)
223 {
224 if (test.IsSuite)
225 foreach (ITest child in test.Tests) this.AddTestCases(child);
226 else
227- {
228- this.vsTestCases.Add(this.TestConverter.ConvertTestCase(test));
229- this.nunitTestCaseMap.Add(test.TestName.UniqueName, test);
230- }
231- }
232-
233- internal virtual void ProcessTfsFilter()
234- {
235-
236- }
237-
238- public static AssemblyFilter Create(string assemblyName, IEnumerable<TestCase> ptestCases)
239- {
240- var filter = new SimpleNameFilter();
241- foreach (TestCase testCase in ptestCases)
242- {
243- filter.Add(testCase.FullyQualifiedName);
244- }
245- return new AssemblyFilter(assemblyName, filter);
246- }
247-
248-
249+ this.LoadedTestCases.Add(this.TestConverter.ConvertTestCase(test));
250+ }
251+
252+ #endregion
253
254 #region IDisposable
255 private bool _Disposed;
256@@ -106,19 +190,17 @@
257 {
258 if (disposing)
259 {
260- if (this.testConverter != null)
261- this.testConverter.Dispose();
262+ if (this.TestConverter != null)
263+ this.TestConverter.Dispose();
264 }
265 }
266 this._Disposed = true;
267 }
268
269- ~AssemblyFilter()
270+ ~AssemblyRunner()
271 {
272 this.Dispose(false);
273 }
274 #endregion
275-
276-
277 }
278 }
279\ No newline at end of file
280
281=== modified file 'src/NUnitTestAdapter/NUnitEventListener.cs'
282--- src/NUnitTestAdapter/NUnitEventListener.cs 2013-08-11 03:20:44 +0000
283+++ src/NUnitTestAdapter/NUnitEventListener.cs 2013-08-14 22:47:33 +0000
284@@ -18,35 +18,17 @@
285 public class NUnitEventListener : MarshalByRefObject, EventListener // Public for testing
286 {
287 private readonly ITestExecutionRecorder testLog;
288- //private string assemblyName;
289- //private readonly Dictionary<string, NUnit.Core.TestNode> nunitTestCases;
290- //private readonly TestConverter testConverter;
291- private AssemblyFilter filter;
292-
293- //public NUnitEventListener(ITestExecutionRecorder testLog, Dictionary<string, NUnit.Core.TestNode> nunitTestCases, string assemblyName, bool isBuildFromTfs)
294- //{
295- // this.testLog = testLog;
296- // this.assemblyName = assemblyName;
297- // this.nunitTestCases = nunitTestCases;
298- // this.testConverter = new TestConverter(assemblyName, nunitTestCases, isBuildFromTfs);
299- //}
300-
301- public NUnitEventListener(ITestExecutionRecorder testLog, AssemblyFilter filter)
302+ private readonly TestConverter testConverter;
303+
304+ public NUnitEventListener(ITestExecutionRecorder testLog, TestConverter testConverter)
305 {
306 this.testLog = testLog;
307- this.filter = filter;
308- //this.assemblyName = assemblyName;
309- //this.nunitTestCases = nunitTestCases;
310- //this.testConverter = new TestConverter(assemblyName, nunitTestCases, isBuildFromTfs);
311+ this.testConverter = testConverter;
312 }
313
314 public void RunStarted(string name, int testCount)
315 {
316 testLog.SendMessage(TestMessageLevel.Informational, "Run started: " + name);
317- //if (EqtTrace.IsVerboseEnabled)
318- //{
319- //EqtTrace.Verbose("Run started: " + name + " : testcount :" + testCount);
320- //}
321 }
322
323 public void RunFinished(Exception exception)
324@@ -81,13 +63,11 @@
325
326 public void TestStarted(TestName testName)
327 {
328- string key = testName.UniqueName;
329+ TestCase ourCase = testConverter.GetCachedTestCase(testName.UniqueName);
330
331- // Simply ignore any TestName not found
332- if (filter.NUnitTestCaseMap.ContainsKey(key))
333+ // Simply ignore any TestName not found in the cache
334+ if (ourCase != null)
335 {
336- var nunitTest = filter.NUnitTestCaseMap[key];
337- var ourCase = filter.TestConverter.ConvertTestCase(nunitTest);
338 this.testLog.RecordStart(ourCase);
339 // Output = testName.FullName + "\r";
340 }
341@@ -96,7 +76,7 @@
342
343 public void TestFinished(NUnit.Core.TestResult result)
344 {
345- TestResult ourResult = filter.TestConverter.ConvertTestResult(result);
346+ TestResult ourResult = testConverter.ConvertTestResult(result);
347 ourResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, Output));
348 this.testLog.RecordEnd(ourResult.TestCase, ourResult.Outcome);
349 this.testLog.RecordResult(ourResult);
350@@ -138,11 +118,5 @@
351 public void UnhandledException(Exception exception)
352 {
353 }
354-
355- //public void Dispose()
356- //{
357- // if (this.testConverter != null)
358- // this.testConverter.Dispose();
359- //}
360 }
361 }
362
363=== modified file 'src/NUnitTestAdapter/NUnitTestAdapter.cs'
364--- src/NUnitTestAdapter/NUnitTestAdapter.cs 2013-08-13 21:16:50 +0000
365+++ src/NUnitTestAdapter/NUnitTestAdapter.cs 2013-08-14 22:47:33 +0000
366@@ -1,31 +1,24 @@
367-// ****************************************************************
368-// Copyright (c) 2011 NUnit Software. All rights reserved.
369-// ****************************************************************
370-
371-using System;
372+// ****************************************************************
373+// Copyright (c) 2011 NUnit Software. All rights reserved.
374+// ****************************************************************
375+
376+using System.Reflection;
377 using System.Runtime.Remoting.Channels;
378 using NUnit.Util;
379-using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
380-
381+
382 namespace NUnit.VisualStudio.TestAdapter
383 {
384- using System.Reflection;
385-
386 /// <summary>
387 /// NUnitTestAdapter is the common base for the
388 /// NUnit discoverer and executor classes.
389 /// </summary>
390 public abstract class NUnitTestAdapter
391 {
392- #region Properties
393-
394- // The logger currently in use
395- protected static IMessageLogger Logger { get; set; }
396+ // Our logger used to display messages
397+ protected TestLogger testLog = new TestLogger();
398
399 // The adapter version
400- private static string Version { get; set; }
401-
402- #endregion
403+ private string adapterVersion;
404
405 #region Constructor
406
407@@ -40,7 +33,7 @@
408
409 ServiceManager.Services.InitializeServices();
410
411- Version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
412+ adapterVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
413 }
414
415 #endregion
416@@ -49,8 +42,8 @@
417
418 protected void Info(string method, string function)
419 {
420- var msg = string.Format("NUnit {0} {1} is {2}", Version, method, function);
421- SendInformationalMessage(msg);
422+ var msg = string.Format("NUnit {0} {1} is {2}", adapterVersion, method, function);
423+ testLog.SendInformationalMessage(msg);
424 }
425
426 protected static void CleanUpRegisteredChannels()
427@@ -59,63 +52,6 @@
428 ChannelServices.UnregisterChannel(chan);
429 }
430
431- protected void AssemblyNotSupportedWarning(string sourceAssembly)
432- {
433- SendWarningMessage("Assembly not supported: " + sourceAssembly);
434- }
435-
436- protected void DependentAssemblyNotFoundWarning(string dependentAssembly, string sourceAssembly)
437- {
438- SendWarningMessage("Dependent Assembly "+dependentAssembly+" of " + sourceAssembly + " not found. Can be ignored if not a NUnit project.");
439- }
440-
441- protected void NUnitLoadError(string sourceAssembly)
442- {
443- SendErrorMessage("NUnit failed to load " + sourceAssembly);
444- }
445-
446- #endregion
447-
448- #region Public Static Methods
449-
450- public static void SendErrorMessage(string message)
451- {
452- SendMessage(TestMessageLevel.Error, message);
453- }
454-
455- public static void SendErrorMessage(string message, Exception ex)
456- {
457- SendMessage(TestMessageLevel.Error, message);
458- SendMessage(TestMessageLevel.Error, ex.ToString());
459- }
460-
461- public static void SendWarningMessage(string message)
462- {
463- SendMessage(TestMessageLevel.Warning, message);
464- }
465-
466- public static void SendInformationalMessage(string message)
467- {
468- SendMessage(TestMessageLevel.Informational, message);
469- }
470-
471- public static void SendDebugMessage(string message)
472- {
473-#if DEBUG
474- SendMessage(TestMessageLevel.Informational, message);
475-#endif
476- }
477-
478- private static void SendMessage(TestMessageLevel level, string message)
479- {
480- // Some of our tests may arrive here without the
481- // Logger having been initialized
482- if (Logger != null)
483- Logger.SendMessage(level, message);
484- }
485-
486- #endregion
487- }
488-
489-
490+ #endregion
491+ }
492 }
493
494=== modified file 'src/NUnitTestAdapter/NUnitTestAdapter.csproj'
495--- src/NUnitTestAdapter/NUnitTestAdapter.csproj 2013-08-13 21:16:50 +0000
496+++ src/NUnitTestAdapter/NUnitTestAdapter.csproj 2013-08-14 22:47:33 +0000
497@@ -68,11 +68,10 @@
498 <Reference Include="System.Xml" />
499 </ItemGroup>
500 <ItemGroup>
501- <Compile Include="AssemblyFilter.cs" />
502+ <Compile Include="AssemblyRunner.cs" />
503 <Compile Include="Internal\Stackframe.cs" />
504 <Compile Include="Internal\StackframeParser.cs" />
505 <Compile Include="Internal\Stacktrace.cs" />
506- <Compile Include="NavigationData.cs" />
507 <Compile Include="NUnitEventListener.cs" />
508 <Compile Include="NUnitTestAdapter.cs" />
509 <Compile Include="NUnitTestDiscoverer.cs" />
510@@ -80,9 +79,11 @@
511 <Compile Include="Properties\AssemblyInfo.cs" />
512 <Compile Include="StackTraceFilter.cs" />
513 <Compile Include="TestConverter.cs" />
514+ <Compile Include="TestLogger.cs" />
515 <Compile Include="TestRunFilter.cs" />
516- <Compile Include="TfsAssemblyFilter.cs" />
517- <Compile Include="TFSTestFilter.cs" />
518+ <Compile Include="TFSTestFilter.cs">
519+ <SubType>Code</SubType>
520+ </Compile>
521 <Compile Include="TraitsFeature.cs" />
522 </ItemGroup>
523 <ItemGroup>
524
525=== modified file 'src/NUnitTestAdapter/NUnitTestDiscoverer.cs'
526--- src/NUnitTestAdapter/NUnitTestDiscoverer.cs 2013-08-13 21:16:50 +0000
527+++ src/NUnitTestAdapter/NUnitTestDiscoverer.cs 2013-08-14 22:47:33 +0000
528@@ -22,10 +22,9 @@
529
530 #region ITestDiscoverer Members
531
532- public void DiscoverTests(IEnumerable<string> sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink)
533+ public void DiscoverTests(IEnumerable<string> sources, IDiscoveryContext discoveryContext, IMessageLogger messageLogger, ITestCaseDiscoverySink discoverySink)
534 {
535- // Set the logger to use for messages
536- Logger = logger;
537+ testLog.Initialize(messageLogger);
538 Info("discovering tests", "started");
539
540 // Ensure any channels registered by other adapters are unregistered
541@@ -33,9 +32,8 @@
542
543 foreach (string sourceAssembly in sources)
544 {
545-#if DEBUG
546- SendInformationalMessage("Processing " + sourceAssembly);
547-#endif
548+ testLog.SendDebugMessage("Processing " + sourceAssembly);
549+
550 TestRunner runner = new TestDomain();
551 TestPackage package = new TestPackage(sourceAssembly);
552
553@@ -43,40 +41,38 @@
554 {
555 if (runner.Load(package))
556 {
557- this.testConverter = new TestConverter(sourceAssembly);
558+ this.testConverter = new TestConverter(testLog, sourceAssembly);
559
560 int cases = ProcessTestCases(runner.Test, discoverySink);
561-#if DEBUG
562- SendInformationalMessage(string.Format("Discovered {0} test cases", cases));
563-#endif
564+
565+ testLog.SendDebugMessage(string.Format("Discovered {0} test cases", cases));
566 }
567 else
568 {
569- NUnitLoadError(sourceAssembly);
570+ testLog.NUnitLoadError(sourceAssembly);
571 }
572 }
573 catch (System.BadImageFormatException)
574 {
575 // we skip the native c++ binaries that we don't support.
576- AssemblyNotSupportedWarning(sourceAssembly);
577+ testLog.AssemblyNotSupportedWarning(sourceAssembly);
578 }
579
580 catch (System.IO.FileNotFoundException ex)
581 {
582 // Probably from the GetExportedTypes in NUnit.core, attempting to find an assembly, not a problem if it is not NUnit here
583- DependentAssemblyNotFoundWarning(ex.FileName, sourceAssembly);
584+ testLog.DependentAssemblyNotFoundWarning(ex.FileName, sourceAssembly);
585 }
586 catch (System.Exception ex)
587 {
588- SendErrorMessage("Exception thrown discovering tests in " + sourceAssembly, ex);
589+ testLog.SendErrorMessage("Exception thrown discovering tests in " + sourceAssembly, ex);
590 }
591 finally
592 {
593- if (testConverter!=null)
594- testConverter.Dispose();
595 runner.Unload();
596 }
597 }
598+
599 Info("discovering test","finished");
600 }
601
602@@ -103,7 +99,7 @@
603 }
604 catch (System.Exception ex)
605 {
606- SendErrorMessage("Exception converting " + test.TestName.FullName, ex);
607+ testLog.SendErrorMessage("Exception converting " + test.TestName.FullName, ex);
608 }
609 }
610
611
612=== modified file 'src/NUnitTestAdapter/NUnitTestExecutor.cs'
613--- src/NUnitTestAdapter/NUnitTestExecutor.cs 2013-08-13 21:16:50 +0000
614+++ src/NUnitTestAdapter/NUnitTestExecutor.cs 2013-08-14 22:47:33 +0000
615@@ -8,7 +8,6 @@
616 using Microsoft.VisualStudio.TestPlatform.ObjectModel;
617 using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
618 using NUnit.Core;
619-using NUnit.Util;
620 // #define LAUNCHDEBUGGER
621
622 namespace NUnit.VisualStudio.TestAdapter
623@@ -22,14 +21,11 @@
624 ///</summary>
625 public const string ExecutorUri = "executor://NUnitTestExecutor";
626
627- /// <summary>
628- /// The current NUnit TestRunner instance
629- /// </summary>
630- private TestRunner runner;
631+ // The currently executing assembly runner
632+ private AssemblyRunner currentRunner;
633
634 #region ITestExecutor
635
636- private bool isCalledFromTfsBuild;
637 /// <summary>
638 /// Called by the Visual Studio IDE to run all tests. Also called by TFS Build
639 /// to run either all or selected tests. In the latter case, a filter is provided
640@@ -40,28 +36,32 @@
641 /// <param name="frameworkHandle">Test log to send results and messages through</param>
642 public void RunTests(IEnumerable<string> sources, IRunContext runContext, IFrameworkHandle frameworkHandle)
643 {
644- Logger = frameworkHandle;
645+ testLog.Initialize(frameworkHandle);
646 Info("executing tests", "started");
647+
648 try
649 {
650 // Ensure any channels registered by other adapters are unregistered
651 CleanUpRegisteredChannels();
652+
653 var tfsfilter = new TFSTestFilter(runContext);
654- isCalledFromTfsBuild = tfsfilter.TfsTestCaseFilterExpression != null;
655- SendDebugMessage("Keepalive:" + runContext.KeepAlive);
656- if (!isCalledFromTfsBuild && runContext.KeepAlive)
657+ testLog.SendDebugMessage("Keepalive:" + runContext.KeepAlive);
658+ if (!tfsfilter.HasTfsFilterValue && runContext.KeepAlive)
659 frameworkHandle.EnableShutdownAfterTestRun = true;
660+
661 foreach (var source in sources)
662 {
663- using (var filter = (isCalledFromTfsBuild) ? new TfsAssemblyFilter(source, runContext) : new AssemblyFilter(source))
664+ using (currentRunner = new AssemblyRunner(testLog, source, runContext))
665 {
666- this.RunAssembly(frameworkHandle, filter);
667+ currentRunner.RunAssembly(frameworkHandle);
668 }
669+
670+ currentRunner = null;
671 }
672 }
673 catch (Exception ex)
674 {
675- SendErrorMessage("Exception " + ex);
676+ testLog.SendErrorMessage("Exception " + ex);
677 }
678 finally
679 {
680@@ -82,93 +82,34 @@
681 Debugger.Launch();
682 #endif
683
684- Logger = frameworkHandle;
685+ testLog.Initialize(frameworkHandle);
686 if (runContext.KeepAlive)
687 frameworkHandle.EnableShutdownAfterTestRun = true;
688 Info("executing tests", "started");
689
690 // Ensure any channels registered by other adapters are unregistered
691 CleanUpRegisteredChannels();
692- isCalledFromTfsBuild = false;
693+
694 var assemblyGroups = tests.GroupBy(tc => tc.Source);
695 foreach (var assemblyGroup in assemblyGroups)
696 {
697- using (var filter = AssemblyFilter.Create(assemblyGroup.Key, assemblyGroup))
698+ using (currentRunner = new AssemblyRunner(testLog, assemblyGroup.Key, assemblyGroup))
699 {
700- this.RunAssembly(frameworkHandle, filter);
701+ currentRunner.RunAssembly(frameworkHandle);
702 }
703
704+ currentRunner = null;
705 }
706+
707 Info("executing tests", "finished");
708
709 }
710
711 void ITestExecutor.Cancel()
712 {
713- if (runner != null && runner.Running)
714- runner.CancelRun();
715- }
716-
717- #endregion
718-
719- #region Private Methods
720-
721-
722-
723- private void RunAssembly(ITestExecutionRecorder testLog, AssemblyFilter filter)
724- {
725-
726- try
727- {
728-#if LAUNCHDEBUGGER
729- Debugger.Launch();
730-#endif
731- this.runner = new TestDomain();
732- var package = new TestPackage(filter.AssemblyName);
733- if (runner.Load(package))
734- {
735- filter.AddTestCases(runner.Test);
736- var listener = new NUnitEventListener(testLog, filter);
737- try
738- {
739- filter.ProcessTfsFilter();
740- runner.Run(listener, filter.NUnitFilter, true, LoggingThreshold.Off);
741- }
742- catch (NullReferenceException)
743- {
744- // this happens during the run when CancelRun is called.
745- SendDebugMessage("Nullref caught");
746- }
747- finally
748- {
749- runner.Unload();
750- }
751- }
752- else
753- {
754- NUnitLoadError(filter.AssemblyName);
755- }
756- }
757- catch (System.BadImageFormatException)
758- {
759- // we skip the native c++ binaries that we don't support.
760- AssemblyNotSupportedWarning(filter.AssemblyName);
761- }
762- catch (System.IO.FileNotFoundException ex)
763- {
764- // Probably from the GetExportedTypes in NUnit.core, attempting to find an assembly, not a problem if it is not NUnit here
765- DependentAssemblyNotFoundWarning(ex.FileName, filter.AssemblyName);
766- }
767- catch (Exception ex)
768- {
769- SendErrorMessage("Exception thrown executing tests in " + filter.AssemblyName, ex);
770- }
771- }
772-
773-
774-
775-
776-
777+ if (currentRunner != null)
778+ currentRunner.CancelRun();
779+ }
780
781 #endregion
782
783@@ -181,12 +122,12 @@
784 {
785 if (disposing)
786 {
787- if (runner != null)
788+ if (currentRunner != null)
789 {
790- runner.Dispose();
791+ currentRunner.Dispose();
792 }
793 }
794- runner = null;
795+ currentRunner = null;
796 }
797 }
798 }
799
800=== removed file 'src/NUnitTestAdapter/NavigationData.cs'
801--- src/NUnitTestAdapter/NavigationData.cs 2013-08-13 21:16:50 +0000
802+++ src/NUnitTestAdapter/NavigationData.cs 1970-01-01 00:00:00 +0000
803@@ -1,131 +0,0 @@
804-using System;
805-using System.Reflection;
806-using Microsoft.VisualStudio.TestPlatform.ObjectModel;
807-using NUnit.Core;
808-
809-namespace NUnit.VisualStudio.TestAdapter
810-{
811- /// <summary>
812- /// The NavigationData class manages the location of navigation data
813- /// for tests. It contains special code for handling async methods.
814- /// </summary>
815- public class NavigationData : IDisposable
816- {
817- private string _sourceAssembly;
818- private DiaSession _diaSession;
819- private bool _tryToCreateDiaSession = true;
820- private Assembly _loadedAssembly;
821- private bool _tryToLoadAssembly = true;
822-
823- public NavigationData(string sourceAssembly)
824- {
825- _sourceAssembly = sourceAssembly;
826- }
827-
828-
829- public DiaNavigationData For(string className, string methodName)
830- {
831- if (this.DiaSession == null) return null;
832-
833- var navData = DiaSession.GetNavigationData(className, methodName);
834-
835- if (navData != null && navData.FileName != null) return navData;
836-
837- // DiaSession returned null. The rest of this code checks to see
838- // if this test is an async method, which needs special handling.
839-
840- if (this.LoadedAssembly == null) return null;
841-
842- var definingType = LoadedAssembly.GetType(className);
843- if (definingType == null) return null;
844-
845- var method = definingType.GetMethod(methodName);
846- if (method == null) return null;
847-
848- var asyncAttribute = Reflect.GetAttribute(method, "System.Runtime.CompilerServices.AsyncStateMachineAttribute", false);
849- if (asyncAttribute == null) return null;
850-
851- PropertyInfo stateMachineTypeProperty = asyncAttribute.GetType().GetProperty("StateMachineType");
852- if (stateMachineTypeProperty == null) return null;
853-
854- Type stateMachineType = stateMachineTypeProperty.GetValue(asyncAttribute, new object[0]) as Type;
855- if (stateMachineType == null) return null;
856-
857- navData = DiaSession.GetNavigationData(stateMachineType.FullName, "MoveNext");
858-
859- return navData;
860- }
861-
862- // NOTE: There is some sort of timing issue involved
863- // in creating the DiaSession. When it is created
864- // in the constructor, an exception is thrown on the
865- // call to GetNavigationData. We don't understand
866- // this, we're just dealing with it.
867- private DiaSession DiaSession
868- {
869- get
870- {
871- if (_tryToCreateDiaSession)
872- {
873- try
874- {
875- _diaSession = new DiaSession(_sourceAssembly);
876- }
877- catch (Exception)
878- {
879- // If this isn't a project type supporting DiaSession,
880- // we just issue a warning. We won't try this again.
881- NUnitTestAdapter.SendWarningMessage("Unable to create DiaSession for " + _sourceAssembly + "\r\nNo source location data will be available for this assembly.");
882- }
883-
884- _tryToCreateDiaSession = false;
885- }
886-
887- return _diaSession;
888- }
889- }
890-
891- // The assembly is only needed here if there async tests
892- // are used. Therefore, we delay loading of the assembly
893- // until it is actually needed.
894- private Assembly LoadedAssembly
895- {
896- get
897- {
898- if (_tryToLoadAssembly)
899- {
900- try
901- {
902- _loadedAssembly = Assembly.LoadFrom(_sourceAssembly);
903- }
904- catch
905- {
906- // If we can't load it for some reason, we issue a warning
907- // and won't try to do it again for the assembly.
908- NUnitTestAdapter.SendWarningMessage("Unable to reflect on " + _sourceAssembly + "\r\nSource data will not be available for some of the tests");
909- }
910-
911- _tryToLoadAssembly = false;
912- }
913-
914- return _loadedAssembly;
915- }
916- }
917-
918- protected virtual void Dispose(bool disposing)
919- {
920- if (disposing)
921- {
922- if (_diaSession != null)
923- _diaSession.Dispose();
924- }
925- _diaSession = null;
926- }
927-
928- public void Dispose()
929- {
930- this.Dispose(true);
931- GC.SuppressFinalize(this);
932- }
933- }
934-}
935
936=== modified file 'src/NUnitTestAdapter/TFSTestFilter.cs'
937--- src/NUnitTestAdapter/TFSTestFilter.cs 2013-08-04 22:51:45 +0000
938+++ src/NUnitTestAdapter/TFSTestFilter.cs 2013-08-14 22:47:33 +0000
939@@ -1,4 +1,8 @@
940-using System;
941+// ****************************************************************
942+// Copyright (c) 2013 NUnit Software. All rights reserved.
943+// ****************************************************************
944+
945+using System;
946 using System.Collections.Generic;
947 using System.Linq;
948 using System.Reflection;
949@@ -68,7 +72,7 @@
950 {
951 get
952 {
953- return TfsTestCaseFilterExpression.TestCaseFilterValue != String.Empty;
954+ return TfsTestCaseFilterExpression != null && TfsTestCaseFilterExpression.TestCaseFilterValue != String.Empty;
955 }
956 }
957 public IEnumerable<TestCase> CheckFilter(IEnumerable<TestCase> tests)
958
959=== modified file 'src/NUnitTestAdapter/TestConverter.cs'
960--- src/NUnitTestAdapter/TestConverter.cs 2013-08-13 21:16:50 +0000
961+++ src/NUnitTestAdapter/TestConverter.cs 2013-08-14 22:47:33 +0000
962@@ -12,24 +12,28 @@
963 namespace NUnit.VisualStudio.TestAdapter
964 {
965 public class TestConverter : IDisposable
966- {
967+ {
968+ private TestLogger logger;
969 private Dictionary<string, TestCase> vsTestCaseMap;
970- private string sourceAssembly;
971- private NavigationData navigationData;
972+ private string sourceAssembly;
973+ private Assembly loadedAssembly;
974+ private bool tryToLoadAssembly = true;
975+ private DiaSession diaSession;
976+ private bool tryToCreateDiaSession = true;
977
978 #region Constructors
979
980- public TestConverter(string sourceAssembly)
981- {
982+ public TestConverter(TestLogger logger, string sourceAssembly)
983+ {
984+ this.logger = logger;
985 this.sourceAssembly = sourceAssembly;
986 this.vsTestCaseMap = new Dictionary<string, TestCase>();
987- this.navigationData = new NavigationData(sourceAssembly);
988 }
989
990- #endregion
991-
992- #region Public Methods
993-
994+ #endregion
995+
996+ #region Public Methods
997+
998 /// <summary>
999 /// Converts an NUnit test into a TestCase for Visual Studio,
1000 /// using the best method available according to the exact
1001@@ -48,14 +52,21 @@
1002 var testCase = MakeTestCaseFromNUnitTest(test);
1003 vsTestCaseMap.Add(test.TestName.UniqueName, testCase);
1004 return testCase;
1005+ }
1006+
1007+ public TestCase GetCachedTestCase(string key)
1008+ {
1009+ if (vsTestCaseMap.ContainsKey(key))
1010+ return vsTestCaseMap[key];
1011+
1012+ logger.SendErrorMessage("Test " + key + " not found in cache");
1013+ return null;
1014 }
1015
1016 public VSTestResult ConvertTestResult(NUnitTestResult result)
1017 {
1018- if (!vsTestCaseMap.ContainsKey(result.Test.TestName.UniqueName))
1019- throw new InvalidOperationException("Trying to convert a TestResult whose Test is not in the cache");
1020-
1021- TestCase ourCase = vsTestCaseMap[result.Test.TestName.UniqueName];
1022+ TestCase ourCase = GetCachedTestCase(result.Test.TestName.UniqueName);
1023+ if (ourCase == null) return null;
1024
1025 VSTestResult ourResult = new VSTestResult(ourCase)
1026 {
1027@@ -97,9 +108,9 @@
1028 {
1029 if (disposing)
1030 {
1031- if (this.navigationData != null) this.navigationData.Dispose();
1032+ if (this.diaSession != null) this.diaSession.Dispose();
1033 }
1034- navigationData = null;
1035+ diaSession = null;
1036 }
1037
1038 #endregion
1039@@ -123,7 +134,7 @@
1040 LineNumber = 0
1041 };
1042
1043- var navData = navigationData.For(nunitTest.ClassName, nunitTest.MethodName);
1044+ var navData = GetNavigationData(nunitTest.ClassName, nunitTest.MethodName);
1045 if (navData != null)
1046 {
1047 testCase.CodeFilePath = navData.FileName;
1048@@ -135,6 +146,40 @@
1049 return testCase;
1050 }
1051
1052+ // public for testing
1053+ public DiaNavigationData GetNavigationData(string className, string methodName)
1054+ {
1055+ if (this.DiaSession == null) return null;
1056+
1057+ var navData = DiaSession.GetNavigationData(className, methodName);
1058+
1059+ if (navData != null && navData.FileName != null) return navData;
1060+
1061+ // DiaSession returned null. The rest of this code checks to see
1062+ // if this test is an async method, which needs special handling.
1063+
1064+ if (this.LoadedAssembly == null) return null;
1065+
1066+ var definingType = LoadedAssembly.GetType(className);
1067+ if (definingType == null) return null;
1068+
1069+ var method = definingType.GetMethod(methodName);
1070+ if (method == null) return null;
1071+
1072+ var asyncAttribute = Reflect.GetAttribute(method, "System.Runtime.CompilerServices.AsyncStateMachineAttribute", false);
1073+ if (asyncAttribute == null) return null;
1074+
1075+ PropertyInfo stateMachineTypeProperty = asyncAttribute.GetType().GetProperty("StateMachineType");
1076+ if (stateMachineTypeProperty == null) return null;
1077+
1078+ Type stateMachineType = stateMachineTypeProperty.GetValue(asyncAttribute, new object[0]) as Type;
1079+ if (stateMachineType == null) return null;
1080+
1081+ navData = DiaSession.GetNavigationData(stateMachineType.FullName, "MoveNext");
1082+
1083+ return navData;
1084+ }
1085+
1086 // Public for testing
1087 public static TestOutcome ResultStateToTestOutcome(ResultState resultState)
1088 {
1089@@ -195,8 +240,64 @@
1090
1091 return exeName == "vstest.executionengine.exe";
1092 }
1093- }
1094-
1095+ }
1096+
1097+ // NOTE: There is some sort of timing issue involved
1098+ // in creating the DiaSession. When it is created
1099+ // in the constructor, an exception is thrown on the
1100+ // call to GetNavigationData. We don't understand
1101+ // this, we're just dealing with it.
1102+ private DiaSession DiaSession
1103+ {
1104+ get
1105+ {
1106+ if (tryToCreateDiaSession)
1107+ {
1108+ try
1109+ {
1110+ diaSession = new DiaSession(sourceAssembly);
1111+ }
1112+ catch (Exception)
1113+ {
1114+ // If this isn't a project type supporting DiaSession,
1115+ // we just issue a warning. We won't try this again.
1116+ logger.SendWarningMessage("Unable to create DiaSession for " + sourceAssembly + "\r\nNo source location data will be available for this assembly.");
1117+ }
1118+
1119+ tryToCreateDiaSession = false;
1120+ }
1121+
1122+ return diaSession;
1123+ }
1124+ }
1125+
1126+ // The assembly is only needed here if there async tests
1127+ // are used. Therefore, we delay loading of the assembly
1128+ // until it is actually needed.
1129+ private Assembly LoadedAssembly
1130+ {
1131+ get
1132+ {
1133+ if (tryToLoadAssembly)
1134+ {
1135+ try
1136+ {
1137+ loadedAssembly = Assembly.LoadFrom(sourceAssembly);
1138+ }
1139+ catch
1140+ {
1141+ // If we can't load it for some reason, we issue a warning
1142+ // and won't try to do it again for the assembly.
1143+ logger.SendWarningMessage("Unable to reflect on " + sourceAssembly + "\r\nSource data will not be available for some of the tests");
1144+ }
1145+
1146+ tryToLoadAssembly = false;
1147+ }
1148+
1149+ return loadedAssembly;
1150+ }
1151+ }
1152+
1153 #endregion
1154 }
1155 }
1156\ No newline at end of file
1157
1158=== added file 'src/NUnitTestAdapter/TestLogger.cs'
1159--- src/NUnitTestAdapter/TestLogger.cs 1970-01-01 00:00:00 +0000
1160+++ src/NUnitTestAdapter/TestLogger.cs 2013-08-14 22:47:33 +0000
1161@@ -0,0 +1,81 @@
1162+// ****************************************************************
1163+// Copyright (c) 2013 NUnit Software. All rights reserved.
1164+// ****************************************************************
1165+
1166+using System;
1167+using System.Collections.Generic;
1168+using System.Linq;
1169+using System.Text;
1170+
1171+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
1172+
1173+namespace NUnit.VisualStudio.TestAdapter
1174+{
1175+ /// <summary>
1176+ /// TestLogger wraps an IMessageLogger and adds various
1177+ /// utility methods for sending messages. Since the
1178+ /// IMessageLogger is only provided when the discovery
1179+ /// and execution objects are called, we use two-phase
1180+ /// construction. Until Initialize is called, the logger
1181+ /// simply swallows all messages without sending them
1182+ /// anywhere.
1183+ /// </summary>
1184+ public class TestLogger : IMessageLogger
1185+ {
1186+ private IMessageLogger messageLogger;
1187+
1188+ public void Initialize(IMessageLogger messageLogger)
1189+ {
1190+ this.messageLogger = messageLogger;
1191+ }
1192+
1193+ public void AssemblyNotSupportedWarning(string sourceAssembly)
1194+ {
1195+ SendWarningMessage("Assembly not supported: " + sourceAssembly);
1196+ }
1197+
1198+ public void DependentAssemblyNotFoundWarning(string dependentAssembly, string sourceAssembly)
1199+ {
1200+ SendWarningMessage("Dependent Assembly " + dependentAssembly + " of " + sourceAssembly + " not found. Can be ignored if not a NUnit project.");
1201+ }
1202+
1203+ public void NUnitLoadError(string sourceAssembly)
1204+ {
1205+ SendErrorMessage("NUnit failed to load " + sourceAssembly);
1206+ }
1207+
1208+ public void SendErrorMessage(string message)
1209+ {
1210+ SendMessage(TestMessageLevel.Error, message);
1211+ }
1212+
1213+ public void SendErrorMessage(string message, Exception ex)
1214+ {
1215+ SendMessage(TestMessageLevel.Error, message);
1216+ SendMessage(TestMessageLevel.Error, ex.ToString());
1217+ }
1218+
1219+ public void SendWarningMessage(string message)
1220+ {
1221+ SendMessage(TestMessageLevel.Warning, message);
1222+ }
1223+
1224+ public void SendInformationalMessage(string message)
1225+ {
1226+ SendMessage(TestMessageLevel.Informational, message);
1227+ }
1228+
1229+ public void SendDebugMessage(string message)
1230+ {
1231+#if DEBUG
1232+ SendMessage(TestMessageLevel.Informational, message);
1233+#endif
1234+ }
1235+
1236+ public void SendMessage(TestMessageLevel testMessageLevel, string message)
1237+ {
1238+ if (messageLogger != null)
1239+ messageLogger.SendMessage(testMessageLevel, message);
1240+ }
1241+ }
1242+}
1243
1244=== removed file 'src/NUnitTestAdapter/TfsAssemblyFilter.cs'
1245--- src/NUnitTestAdapter/TfsAssemblyFilter.cs 2013-08-11 03:20:44 +0000
1246+++ src/NUnitTestAdapter/TfsAssemblyFilter.cs 1970-01-01 00:00:00 +0000
1247@@ -1,32 +0,0 @@
1248-namespace NUnit.VisualStudio.TestAdapter
1249-{
1250- using Microsoft.VisualStudio.TestPlatform.ObjectModel;
1251- using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
1252-
1253- using NUnit.Core.Filters;
1254-
1255- public class TfsAssemblyFilter : AssemblyFilter
1256- {
1257- private readonly TFSTestFilter tfsfilter;
1258- public TfsAssemblyFilter(string assemblyName, IRunContext runContext)
1259- : base(assemblyName)
1260- {
1261- this.tfsfilter = new TFSTestFilter(runContext);
1262- }
1263-
1264- internal override void ProcessTfsFilter()
1265- {
1266- if ( this.tfsfilter.HasTfsFilterValue)
1267- {
1268- var filteredTestCases = this.tfsfilter.CheckFilter(this.VsTestCases);
1269- var filter = new SimpleNameFilter();
1270- foreach (TestCase testCase in filteredTestCases)
1271- {
1272- filter.Add(testCase.FullyQualifiedName);
1273- }
1274- this.NUnitFilter = filter;
1275- }
1276- }
1277-
1278- }
1279-}
1280\ No newline at end of file
1281
1282=== modified file 'src/NUnitTestAdapter/TraitsFeature.cs'
1283--- src/NUnitTestAdapter/TraitsFeature.cs 2013-08-13 21:16:50 +0000
1284+++ src/NUnitTestAdapter/TraitsFeature.cs 2013-08-14 22:47:33 +0000
1285@@ -1,4 +1,8 @@
1286-using System;
1287+// ****************************************************************
1288+// Copyright (c) 2013 NUnit Software. All rights reserved.
1289+// ****************************************************************
1290+
1291+using System;
1292 using System.Collections.Generic;
1293 using System.Reflection;
1294 using Microsoft.VisualStudio.TestPlatform.ObjectModel;
1295
1296=== renamed file 'src/NUnitTestAdapterTests/AssemblyFilterTests.cs' => 'src/NUnitTestAdapterTests/AssemblyRunnerTests.cs'
1297--- src/NUnitTestAdapterTests/AssemblyFilterTests.cs 2013-08-12 23:47:42 +0000
1298+++ src/NUnitTestAdapterTests/AssemblyRunnerTests.cs 2013-08-14 22:47:33 +0000
1299@@ -4,28 +4,19 @@
1300 // ****************************************************************
1301 using System;
1302 using System.Collections.Generic;
1303-using System.Linq;
1304-using System.Text;
1305-using System.Threading.Tasks;
1306-using System.IO;
1307 using Microsoft.VisualStudio.TestPlatform.ObjectModel;
1308-using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
1309-using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
1310 using NUnit.Framework;
1311-using System.Collections;
1312
1313
1314 namespace NUnit.VisualStudio.TestAdapter.Tests
1315 {
1316- using System.Diagnostics;
1317 using System.Reflection;
1318
1319 using NUnit.Core;
1320 using NUnit.Core.Filters;
1321- using NUnit.VisualStudio.TestAdapter.Tests.Fakes;
1322
1323 [TestFixture]
1324- public class AssemblyFilterTests
1325+ public class AssemblyRunnerTests
1326 {
1327 private readonly static Uri EXECUTOR_URI = new Uri(NUnitTestExecutor.ExecutorUri);
1328
1329@@ -55,28 +46,33 @@
1330 [Test]
1331 public void VerifyConstruction1()
1332 {
1333- var target = new AssemblyFilter("test");
1334- Assert.That(target.NUnitFilter.IsEmpty, Is.True);
1335+ var runner = new AssemblyRunner(new TestLogger(), "test");
1336+ Assert.That(runner.NUnitFilter.IsEmpty, Is.True);
1337 }
1338
1339 [Test]
1340 public void VerifyConstruction2()
1341 {
1342- var sf = new SimpleNameFilter();
1343- var target2 = new AssemblyFilter("test", sf);
1344- Assert.That(target2.NUnitFilter.IsEmpty, Is.False);
1345+ var t1 = new TestCase(fakeTest1.TestName.FullName, EXECUTOR_URI, "test");
1346+ var t2 = new TestCase(fakeTest2.TestName.FullName, EXECUTOR_URI, "test");
1347+ var list = new List<TestCase> { t1, t2 };
1348+ var runner = new AssemblyRunner(new TestLogger(), "test", list);
1349+ Assert.False(runner.NUnitFilter.IsEmpty);
1350+ Assert.That(runner.NUnitFilter, Is.TypeOf<SimpleNameFilter>());
1351+ Assert.True(runner.NUnitFilter.Match(fakeTest1));
1352+ Assert.True(runner.NUnitFilter.Match(fakeTest2));
1353 }
1354
1355+ // TODO: Instead of using AddTestCases, we should be loading an actual assembly
1356+
1357 [Test]
1358 public void AddsNonFilteredCorrectly()
1359 {
1360- var target = new AssemblyFilter("test");
1361- target.AddTestCases(fakeTest1);
1362- target.AddTestCases(fakeTest2);
1363- Assert.That(target.NUnitFilter.IsEmpty,Is.True,"NUnitfilter has been touched");
1364- Assert.That(target.VsTestCases.Count,Is.EqualTo(2),"We should have had 2 test cases here");
1365- Assert.That(target.NUnitTestCaseMap.ContainsKey(fakeTest1.TestName.UniqueName), Is.True, "FakeTestMethod1 is not in the map");
1366- Assert.That(target.NUnitTestCaseMap.ContainsKey(fakeTest2.TestName.UniqueName), Is.True, "FakeTestMethod2 is not in the map");
1367+ var runner = new AssemblyRunner(new TestLogger(), "test");
1368+ runner.AddTestCases(fakeTest1);
1369+ runner.AddTestCases(fakeTest2);
1370+ Assert.That(runner.NUnitFilter.IsEmpty,Is.True,"NUnitfilter has been touched");
1371+ Assert.That(runner.LoadedTestCases.Count,Is.EqualTo(2),"We should have had 2 test cases here");
1372 }
1373
1374 [Test]
1375@@ -85,21 +81,11 @@
1376 var t1 = new TestCase(fakeTest1.TestName.FullName, EXECUTOR_URI, "test");
1377 var t2 = new TestCase(fakeTest2.TestName.FullName, EXECUTOR_URI, "test");
1378 var list = new List<TestCase> { t1, t2 };
1379- var target = AssemblyFilter.Create("test",list);
1380- target.AddTestCases(fakeTest1);
1381- target.AddTestCases(fakeTest2);
1382- Assert.That(target.NUnitFilter.IsEmpty, Is.False, "NUnitfilter should not be empty, we have added testcases");
1383- Assert.That(target.VsTestCases.Count, Is.EqualTo(2), "We should have had 2 converted MS test cases here");
1384- Assert.That(target.NUnitTestCaseMap.ContainsKey(fakeTest1.TestName.UniqueName), Is.True, "FakeTestMethod1 is not in the map");
1385- Assert.That(target.NUnitTestCaseMap.ContainsKey(fakeTest2.TestName.UniqueName), Is.True, "FakeTestMethod2 is not in the map");
1386- }
1387-
1388- [Test]
1389- public void TfsAssemblyFilterIsCorrectlyConstructed()
1390- {
1391- var target = new TfsAssemblyFilter("test", new FakeRunContext());
1392- Assert.That(target.NUnitFilter.IsEmpty,Is.True,"NUnitFilter should be empty before processing");
1393- }
1394-
1395+ var runner = new AssemblyRunner(new TestLogger(), "test",list);
1396+ runner.AddTestCases(fakeTest1);
1397+ runner.AddTestCases(fakeTest2);
1398+ Assert.That(runner.NUnitFilter.IsEmpty, Is.False, "NUnitfilter should not be empty, we have added testcases");
1399+ Assert.That(runner.LoadedTestCases.Count, Is.EqualTo(2), "We should have had 2 converted MS test cases here");
1400+ }
1401 }
1402 }
1403
1404=== modified file 'src/NUnitTestAdapterTests/NUnitEventListenerTests.cs'
1405--- src/NUnitTestAdapterTests/NUnitEventListenerTests.cs 2013-08-12 23:47:42 +0000
1406+++ src/NUnitTestAdapterTests/NUnitEventListenerTests.cs 2013-08-14 22:47:33 +0000
1407@@ -33,8 +33,8 @@
1408
1409 private NUnitEventListener listener;
1410 private FakeFrameworkHandle testLog;
1411+ private TestConverter testConverter;
1412
1413- private AssemblyFilter filter;
1414 [SetUp]
1415 public void SetUp()
1416 {
1417@@ -47,10 +47,12 @@
1418
1419 testLog = new FakeFrameworkHandle();
1420
1421- filter = new AssemblyFilter(THIS_ASSEMBLY_PATH);
1422- filter.AddTestCases(fakeNUnitTest);
1423+ testConverter = new TestConverter(new TestLogger(), THIS_ASSEMBLY_PATH);
1424+
1425+ testConverter.ConvertTestCase(fakeNUnitTest);
1426+ Assert.NotNull(testConverter.GetCachedTestCase(fakeNUnitTest.TestName.UniqueName));
1427
1428- this.listener = new NUnitEventListener(testLog, filter);
1429+ this.listener = new NUnitEventListener(testLog, testConverter);
1430 }
1431
1432 #region TestStarted Tests
1433
1434=== modified file 'src/NUnitTestAdapterTests/NUnitTestAdapterTests.csproj'
1435--- src/NUnitTestAdapterTests/NUnitTestAdapterTests.csproj 2013-08-04 22:51:45 +0000
1436+++ src/NUnitTestAdapterTests/NUnitTestAdapterTests.csproj 2013-08-14 22:47:33 +0000
1437@@ -68,7 +68,7 @@
1438 <Reference Include="System.Xml" />
1439 </ItemGroup>
1440 <ItemGroup>
1441- <Compile Include="AssemblyFilterTests.cs" />
1442+ <Compile Include="AssemblyRunnerTests.cs" />
1443 <Compile Include="AsyncTests.cs" />
1444 <Compile Include="NavigationTestData.cs" />
1445 <Compile Include="NavigationDataTests.cs" />
1446
1447=== modified file 'src/NUnitTestAdapterTests/NavigationDataTests.cs'
1448--- src/NUnitTestAdapterTests/NavigationDataTests.cs 2012-12-22 17:26:33 +0000
1449+++ src/NUnitTestAdapterTests/NavigationDataTests.cs 2013-08-14 22:47:33 +0000
1450@@ -10,20 +10,20 @@
1451 private static readonly string THIS_ASSEMBLY_PATH =
1452 Path.GetFullPath("NUnit.VisualStudio.TestAdapter.Tests.dll");
1453
1454- NavigationData navData;
1455+ TestConverter testConverter;
1456
1457 const string prefix = "NUnit.VisualStudio.TestAdapter.Tests.NavigationTestData";
1458
1459- [TestFixtureSetUp]
1460- public void InitializeNavigationData()
1461+ [SetUp]
1462+ public void SetUp()
1463 {
1464- navData = new NavigationData(THIS_ASSEMBLY_PATH);
1465+ testConverter = new TestConverter(new TestLogger(), THIS_ASSEMBLY_PATH);
1466 }
1467
1468- [TestFixtureTearDown]
1469- public void DisposeNavigationData()
1470+ [TearDown]
1471+ public void TearDown()
1472 {
1473- navData.Dispose();
1474+ testConverter.Dispose();
1475 }
1476
1477 [TestCase("", "EmptyMethod_OneLine", 9, 9, 9, 9)]
1478@@ -48,13 +48,9 @@
1479 [TestCase("+GenericFixture`2+DoublyNested`1", "WriteAllThree", 151, 152, 153, 153)]
1480 public void VerifyNavigationData(string suffix, string methodName, int minLineDebug, int minLineRelease, int maxLineRelease, int maxLineDebug)
1481 {
1482- // We put this here because the Test Window will not
1483- // display a failure occuring in the fixture setup method
1484- Assert.NotNull(navData, "NavigationData could not be created");
1485-
1486 // Get the navigation data - ensure names are spelled correctly!
1487 var className = prefix + suffix;
1488- var data = navData.For(className, methodName);
1489+ var data = testConverter.GetNavigationData(className, methodName);
1490 Assert.NotNull(data, "Unable to retrieve navigation data");
1491
1492 // Verify the navigation data
1493
1494=== modified file 'src/NUnitTestAdapterTests/TestConverterTests.cs'
1495--- src/NUnitTestAdapterTests/TestConverterTests.cs 2013-08-12 23:47:42 +0000
1496+++ src/NUnitTestAdapterTests/TestConverterTests.cs 2013-08-14 22:47:33 +0000
1497@@ -2,6 +2,7 @@
1498 // Copyright (c) 2011 NUnit Software. All rights reserved.
1499 // ****************************************************************
1500
1501+using System;
1502 using System.Collections.Generic;
1503 using System.IO;
1504 using System.Reflection;
1505@@ -25,7 +26,7 @@
1506
1507 // NOTE: If the location of the FakeTestCase method in the
1508 // file changes, update the value of FAKE_LINE_NUMBER.
1509- private static readonly int FAKE_LINE_NUMBER = 29;
1510+ private static readonly int FAKE_LINE_NUMBER = 30;
1511 private void FakeTestCase() { } // FAKE_LINE_NUMBER SHOULD BE THIS LINE
1512
1513 private ITest fakeNUnitTest;
1514@@ -48,7 +49,13 @@
1515 var fixtureNode = new TestNode(nunitFixture);
1516 fakeNUnitTest = (ITest)fixtureNode.Tests[0];
1517
1518- testConverter = new TestConverter(THIS_ASSEMBLY_PATH);
1519+ testConverter = new TestConverter(new TestLogger(), THIS_ASSEMBLY_PATH);
1520+ }
1521+
1522+ [TearDown]
1523+ public void TearDown()
1524+ {
1525+ testConverter.Dispose();
1526 }
1527
1528 [Test]
1529@@ -56,12 +63,24 @@
1530 {
1531 var testCase = testConverter.ConvertTestCase(fakeNUnitTest);
1532
1533- CheckBasicInfo(testCase);
1534-
1535- Assert.That(testCase.CodeFilePath, Is.SamePath(THIS_CODE_FILE));
1536- Assert.That(testCase.LineNumber, Is.EqualTo(FAKE_LINE_NUMBER));
1537-
1538- CheckTraits(testCase);
1539+ CheckTestCase(testCase);
1540+ }
1541+
1542+ [Test]
1543+ public void ConvertedTestCaseIsCached()
1544+ {
1545+ testConverter.ConvertTestCase(fakeNUnitTest);
1546+ var testCase = testConverter.GetCachedTestCase(fakeNUnitTest.TestName.UniqueName);
1547+
1548+ CheckTestCase(testCase);
1549+ }
1550+
1551+ [Test]
1552+ public void CannotMakeTestResultWhenTestCaseIsNotInCache()
1553+ {
1554+ var nunitResult = new NUnitTestResult(fakeNUnitTest);
1555+ var testResult = testConverter.ConvertTestResult(nunitResult);
1556+ Assert.Null(testResult);
1557 }
1558
1559 [Test]
1560@@ -70,31 +89,33 @@
1561 // This should put the TestCase in the cache
1562 var cachedTestCase = testConverter.ConvertTestCase(fakeNUnitTest);
1563
1564- var nunitResult = new NUnitTestResult(fakeNUnitTest);
1565+ var nunitResult = new NUnitTestResult(fakeNUnitTest);
1566+ nunitResult.SetResult(ResultState.Success, "It passed!", null);
1567+ nunitResult.Time = 1.234;
1568+
1569 var testResult = testConverter.ConvertTestResult(nunitResult);
1570 var testCase = testResult.TestCase;
1571
1572 Assert.That(testCase, Is.SameAs(cachedTestCase));
1573
1574- CheckBasicInfo(testCase);
1575-
1576- Assert.That(testCase.CodeFilePath, Is.SamePath(THIS_CODE_FILE));
1577- Assert.That(testCase.LineNumber, Is.EqualTo(FAKE_LINE_NUMBER));
1578-
1579- CheckTraits(testCase);
1580+ CheckTestCase(testCase);
1581+
1582+ Assert.That(testResult.Outcome, Is.EqualTo(TestOutcome.Passed));
1583+ Assert.That(testResult.ErrorMessage, Is.EqualTo("It passed!"));
1584+ Assert.That(testResult.Duration, Is.EqualTo(TimeSpan.FromSeconds(1.234)));
1585 }
1586
1587- private static void CheckBasicInfo(TestCase testCase)
1588+ private static void CheckTestCase(TestCase testCase)
1589 {
1590 Assert.That(testCase.FullyQualifiedName, Is.EqualTo("NUnit.VisualStudio.TestAdapter.Tests.TestConverterTests.FakeTestCase"));
1591 Assert.That(testCase.DisplayName, Is.EqualTo("FakeTestCase"));
1592- Assert.That(testCase.Source, Is.SamePath(THIS_ASSEMBLY_PATH));
1593- }
1594+ Assert.That(testCase.Source, Is.SamePath(THIS_ASSEMBLY_PATH));
1595+
1596+ Assert.That(testCase.CodeFilePath, Is.SamePath(THIS_CODE_FILE));
1597+ Assert.That(testCase.LineNumber, Is.EqualTo(FAKE_LINE_NUMBER));
1598
1599- // Check traits using reflection, since the feature was added
1600- // in an update to VisualStudio and may not be present.
1601- private static void CheckTraits(TestCase testCase)
1602- {
1603+ // Check traits using reflection, since the feature was added
1604+ // in an update to VisualStudio and may not be present.
1605 if (TraitsFeature.IsSupported)
1606 {
1607 var traitList = new List<string>();

Subscribers

People subscribed via source and target branches