Browse Source

Use named pipe instead of temporary file for sending the unit tests results to SharpDevelop.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
81361f7a12
  1. 2
      src/AddIns/Analysis/UnitTesting/Interfaces/IUnitTestProcessRunner.cs
  2. 5
      src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestProcessRunner.cs
  3. 10
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs
  4. 13
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestDebugger.cs
  5. 19
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestRunner.cs
  6. 8
      src/AddIns/Analysis/UnitTesting/Test/NUnit/NUnitConsoleCommandLineTests.cs
  7. 93
      src/AddIns/Analysis/UnitTesting/Test/TestRunner/TestResultsReaderTests.cs
  8. 20
      src/AddIns/Analysis/UnitTesting/TestRunner/ITestResultsMonitor.cs
  9. 24
      src/AddIns/Analysis/UnitTesting/TestRunner/TestDebuggerBase.cs
  10. 28
      src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBase.cs
  11. 12
      src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBaseContext.cs
  12. 178
      src/AddIns/Analysis/UnitTesting/TestRunner/TestResultsMonitor.cs
  13. 122
      src/AddIns/Analysis/UnitTesting/TestRunner/TestResultsReader.cs
  14. 11
      src/AddIns/Analysis/UnitTesting/TestRunner/TestRunnerBase.cs
  15. 4
      src/AddIns/Analysis/UnitTesting/UnitTesting.csproj
  16. 23
      src/Main/Base/Project/Src/Util/ProcessRunner.cs
  17. 2
      src/Tools/NUnit/buildnunitconsole.bat
  18. BIN
      src/Tools/NUnit/nunit-console-dotnet2-x86.exe
  19. BIN
      src/Tools/NUnit/nunit-console-dotnet2.exe
  20. BIN
      src/Tools/NUnit/nunit-console-x86.exe
  21. BIN
      src/Tools/NUnit/nunit-console.exe
  22. 8
      src/Tools/NUnit/nunit-console/ExtendedConsoleOptions.cs
  23. 9
      src/Tools/NUnit/nunit-console/ExtendedConsoleUi.cs
  24. 8
      src/Tools/NUnit/nunit-console/nunit-console.csproj

2
src/AddIns/Analysis/UnitTesting/Interfaces/IUnitTestProcessRunner.cs

@ -7,7 +7,7 @@ using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting namespace ICSharpCode.UnitTesting
{ {
public interface IUnitTestProcessRunner public interface IUnitTestProcessRunner : IDisposable
{ {
bool LogStandardOutputAndError { get; set; } bool LogStandardOutputAndError { get; set; }
string WorkingDirectory { get; set; } string WorkingDirectory { get; set; }

5
src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestProcessRunner.cs

@ -54,5 +54,10 @@ namespace ICSharpCode.UnitTesting
{ {
runner.Kill(); runner.Kill();
} }
public void Dispose()
{
runner.Dispose();
}
} }
} }

10
src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs

@ -141,9 +141,9 @@ namespace ICSharpCode.UnitTesting
public string Test; public string Test;
/// <summary> /// <summary>
/// File to write test results to. /// Pipe to write test results to.
/// </summary> /// </summary>
public string Results; public string ResultsPipe;
/// <summary> /// <summary>
/// The namespace that tests need to be a part of if they are to /// The namespace that tests need to be a part of if they are to
@ -206,9 +206,9 @@ namespace ICSharpCode.UnitTesting
b.Append(XmlOutputFile); b.Append(XmlOutputFile);
b.Append('"'); b.Append('"');
} }
if (Results != null) { if (ResultsPipe != null) {
b.Append(" /results=\""); b.Append(" /pipe=\"");
b.Append(Results); b.Append(ResultsPipe);
b.Append('"'); b.Append('"');
} }
string run = null; string run = null;

13
src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestDebugger.cs

@ -18,16 +18,16 @@ namespace ICSharpCode.UnitTesting
public NUnitTestDebugger() public NUnitTestDebugger()
: this(new UnitTestDebuggerService(), : this(new UnitTestDebuggerService(),
SD.MessageService, SD.MessageService,
new TestResultsMonitor(), new TestResultsReader(),
UnitTestingOptions.Instance.Clone()) UnitTestingOptions.Instance.Clone())
{ {
} }
public NUnitTestDebugger(IUnitTestDebuggerService debuggerService, public NUnitTestDebugger(IUnitTestDebuggerService debuggerService,
IMessageService messageService, IMessageService messageService,
ITestResultsMonitor testResultsMonitor, ITestResultsReader testResultsReader,
UnitTestingOptions options) UnitTestingOptions options)
: base(debuggerService, messageService, testResultsMonitor) : base(debuggerService, messageService, testResultsReader)
{ {
this.options = options; this.options = options;
} }
@ -35,7 +35,7 @@ namespace ICSharpCode.UnitTesting
protected override ProcessStartInfo GetProcessStartInfo(IEnumerable<ITest> selectedTests) protected override ProcessStartInfo GetProcessStartInfo(IEnumerable<ITest> selectedTests)
{ {
NUnitConsoleApplication app = new NUnitConsoleApplication(selectedTests, options); NUnitConsoleApplication app = new NUnitConsoleApplication(selectedTests, options);
app.Results = base.TestResultsMonitor.FileName; app.ResultsPipe = base.TestResultsReader.PipeName;
return app.GetProcessStartInfo(); return app.GetProcessStartInfo();
} }
@ -43,5 +43,10 @@ namespace ICSharpCode.UnitTesting
{ {
return new NUnitTestResult(testResult); return new NUnitTestResult(testResult);
} }
public override int GetExpectedNumberOfTestResults(IEnumerable<ITest> selectedTests)
{
return NUnitTestRunner.GetNumberOfTestMethods(selectedTests);
}
} }
} }

19
src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestRunner.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.UnitTesting
protected override ProcessStartInfo GetProcessStartInfo(IEnumerable<ITest> selectedTests) protected override ProcessStartInfo GetProcessStartInfo(IEnumerable<ITest> selectedTests)
{ {
NUnitConsoleApplication app = new NUnitConsoleApplication(selectedTests, options); NUnitConsoleApplication app = new NUnitConsoleApplication(selectedTests, options);
app.Results = base.TestResultsMonitor.FileName; app.ResultsPipe = base.TestResultsReader.PipeName;
return app.GetProcessStartInfo(); return app.GetProcessStartInfo();
} }
@ -38,5 +38,22 @@ namespace ICSharpCode.UnitTesting
{ {
return new NUnitTestResult(testResult); return new NUnitTestResult(testResult);
} }
public override int GetExpectedNumberOfTestResults(IEnumerable<ITest> selectedTests)
{
return GetNumberOfTestMethods(selectedTests);
}
public static int GetNumberOfTestMethods(IEnumerable<ITest> selectedTests)
{
int count = 0;
foreach (ITest test in selectedTests) {
if (test is NUnitTestMethod)
count++;
else
count += GetNumberOfTestMethods(test.NestedTests);
}
return count;
}
} }
} }

8
src/AddIns/Analysis/UnitTesting/Test/NUnit/NUnitConsoleCommandLineTests.cs

@ -38,9 +38,9 @@ namespace UnitTesting.Tests.NUnit
app.NoLogo = false; app.NoLogo = false;
app.ShadowCopy = true; app.ShadowCopy = true;
app.NoXmlOutputFile = false; app.NoXmlOutputFile = false;
app.Results = @"C:\results.txt"; app.ResultsPipe = @"C:\results.txt";
string expectedCommandLine = "\"C:\\Projects\\MyTests\\MyTests.dll\" /results=\"C:\\results.txt\""; string expectedCommandLine = "\"C:\\Projects\\MyTests\\MyTests.dll\" /pipe=\"C:\\results.txt\"";
Assert.AreEqual(expectedCommandLine, app.GetArguments()); Assert.AreEqual(expectedCommandLine, app.GetArguments());
} }
@ -229,13 +229,13 @@ namespace UnitTesting.Tests.NUnit
app.Assemblies.Add("SecondAssembly.dll"); app.Assemblies.Add("SecondAssembly.dll");
app.NoLogo = false; app.NoLogo = false;
app.ShadowCopy = true; app.ShadowCopy = true;
app.Results = @"C:\results.txt"; app.ResultsPipe = @"C:\results.txt";
app.NoXmlOutputFile = false; app.NoXmlOutputFile = false;
string expectedCommandLine = string expectedCommandLine =
"\"C:\\Projects\\MyTests\\MyTests.dll\" " + "\"C:\\Projects\\MyTests\\MyTests.dll\" " +
"\"SecondAssembly.dll\" " + "\"SecondAssembly.dll\" " +
"/results=\"C:\\results.txt\""; "/pipe=\"C:\\results.txt\"";
Assert.AreEqual(expectedCommandLine, app.GetArguments()); Assert.AreEqual(expectedCommandLine, app.GetArguments());
} }

93
src/AddIns/Analysis/UnitTesting/Test/TestRunner/TestResultsReaderTests.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using ICSharpCode.UnitTesting; using ICSharpCode.UnitTesting;
using NUnit.Framework; using NUnit.Framework;
@ -17,10 +18,12 @@ namespace UnitTesting.Tests.TestRunner
string resultsText = "Name: MyTest\r\n" + string resultsText = "Name: MyTest\r\n" +
"Result: Success\r\n"; "Result: Success\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length); Assert.AreEqual(1, results.Count);
TestResult result = results[0]; TestResult result = results[0];
Assert.AreEqual("MyTest", result.Name); Assert.AreEqual("MyTest", result.Name);
@ -34,10 +37,12 @@ namespace UnitTesting.Tests.TestRunner
string resultsText = "Name: MyTest\r\n" + string resultsText = "Name: MyTest\r\n" +
"Result: Ignored\r\n"; "Result: Ignored\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length); Assert.AreEqual(1, results.Count);
TestResult result = results[0]; TestResult result = results[0];
Assert.AreEqual("MyTest", result.Name); Assert.AreEqual("MyTest", result.Name);
@ -45,7 +50,7 @@ namespace UnitTesting.Tests.TestRunner
Assert.IsFalse(result.IsSuccess); Assert.IsFalse(result.IsSuccess);
Assert.AreEqual(TestResultType.Ignored, result.ResultType); Assert.AreEqual(TestResultType.Ignored, result.ResultType);
} }
/*
[Test] [Test]
public void OneTestPassInParts() public void OneTestPassInParts()
{ {
@ -70,17 +75,19 @@ namespace UnitTesting.Tests.TestRunner
Assert.AreEqual("MyTest", result.Name); Assert.AreEqual("MyTest", result.Name);
Assert.IsTrue(result.IsSuccess); Assert.IsTrue(result.IsSuccess);
} }
*/
[Test] [Test]
public void OneTestFailure() public void OneTestFailure()
{ {
string resultsText = "Name: MyTest\r\n" + string resultsText = "Name: MyTest\r\n" +
"Result: Failure\r\n"; "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length); Assert.AreEqual(1, results.Count);
TestResult result = results[0]; TestResult result = results[0];
Assert.AreEqual("MyTest", result.Name); Assert.AreEqual("MyTest", result.Name);
@ -97,10 +104,12 @@ namespace UnitTesting.Tests.TestRunner
"Message: Should not be 0.\r\n" + "Message: Should not be 0.\r\n" +
"Result: Failure\r\n"; "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length); Assert.AreEqual(1, results.Count);
TestResult result = results[0]; TestResult result = results[0];
Assert.AreEqual("Test", result.Name); Assert.AreEqual("Test", result.Name);
@ -115,10 +124,12 @@ namespace UnitTesting.Tests.TestRunner
"StackTrace: stack trace\r\n" + "StackTrace: stack trace\r\n" +
"Result: Failure\r\n"; "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length); Assert.AreEqual(1, results.Count);
TestResult result = results[0]; TestResult result = results[0];
Assert.AreEqual("Test", result.Name); Assert.AreEqual("Test", result.Name);
@ -131,10 +142,12 @@ namespace UnitTesting.Tests.TestRunner
{ {
string resultsText = "Result: Failure\r\n"; string resultsText = "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(0, results.Length); Assert.AreEqual(0, results.Count);
} }
[Test] [Test]
@ -144,10 +157,12 @@ namespace UnitTesting.Tests.TestRunner
"Name: Test\r\n" + "Name: Test\r\n" +
"Result: Failure\r\n"; "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length); Assert.AreEqual(1, results.Count);
TestResult result = results[0]; TestResult result = results[0];
Assert.AreEqual("Test", result.Name); Assert.AreEqual("Test", result.Name);
@ -162,10 +177,12 @@ namespace UnitTesting.Tests.TestRunner
" Should be 1.\r\n" + " Should be 1.\r\n" +
"Result: Failure\r\n"; "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length); Assert.AreEqual(1, results.Count);
TestResult result = results[0]; TestResult result = results[0];
Assert.AreEqual("Test", result.Name); Assert.AreEqual("Test", result.Name);
@ -182,10 +199,12 @@ namespace UnitTesting.Tests.TestRunner
" End of message.\r\n" + " End of message.\r\n" +
"Result: Failure\r\n"; "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length); Assert.AreEqual(1, results.Count);
TestResult result = results[0]; TestResult result = results[0];
Assert.AreEqual("Test", result.Name); Assert.AreEqual("Test", result.Name);
@ -201,10 +220,12 @@ namespace UnitTesting.Tests.TestRunner
"Name: MyTest2\r\n" + "Name: MyTest2\r\n" +
"Result: Failure\r\n"; "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(2, results.Length); Assert.AreEqual(2, results.Count);
TestResult result1 = results[0]; TestResult result1 = results[0];
Assert.AreEqual("MyTest1", result1.Name); Assert.AreEqual("MyTest1", result1.Name);
@ -228,10 +249,12 @@ namespace UnitTesting.Tests.TestRunner
" ThirdLine\r\n" + " ThirdLine\r\n" +
"Result: Failure\r\n"; "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader(); TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
TestResult[] results = reader.Read(resultsText); List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(2, results.Length); Assert.AreEqual(2, results.Count);
TestResult result1 = results[0]; TestResult result1 = results[0];
Assert.AreEqual("MyTest1", result1.Name); Assert.AreEqual("MyTest1", result1.Name);

20
src/AddIns/Analysis/UnitTesting/TestRunner/ITestResultsMonitor.cs

@ -1,20 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.UnitTesting
{
public interface ITestResultsMonitor : IDisposable
{
event EventHandler<TestFinishedEventArgs> TestFinished;
string FileName { get; set; }
void Stop();
void Start();
void Read();
long InitialFilePosition { get; set; }
}
}

24
src/AddIns/Analysis/UnitTesting/TestRunner/TestDebuggerBase.cs

@ -16,29 +16,29 @@ namespace ICSharpCode.UnitTesting
IUnitTestDebuggerService debuggerService; IUnitTestDebuggerService debuggerService;
IMessageService messageService; IMessageService messageService;
IDebugger debugger; IDebugger debugger;
ITestResultsMonitor testResultsMonitor; ITestResultsReader testResultsReader;
public TestDebuggerBase() public TestDebuggerBase()
: this(new UnitTestDebuggerService(), : this(new UnitTestDebuggerService(),
SD.MessageService, SD.MessageService,
new TestResultsMonitor()) new TestResultsReader())
{ {
} }
public TestDebuggerBase(IUnitTestDebuggerService debuggerService, public TestDebuggerBase(IUnitTestDebuggerService debuggerService,
IMessageService messageService, IMessageService messageService,
ITestResultsMonitor testResultsMonitor) ITestResultsReader testResultsReader)
{ {
this.debuggerService = debuggerService; this.debuggerService = debuggerService;
this.messageService = messageService; this.messageService = messageService;
this.testResultsMonitor = testResultsMonitor; this.testResultsReader = testResultsReader;
this.debugger = debuggerService.CurrentDebugger; this.debugger = debuggerService.CurrentDebugger;
testResultsMonitor.TestFinished += OnTestFinished; testResultsReader.TestFinished += OnTestFinished;
} }
protected ITestResultsMonitor TestResultsMonitor { protected ITestResultsReader TestResultsReader {
get { return testResultsMonitor; } get { return testResultsReader; }
} }
public override void Start(IEnumerable<ITest> selectedTests) public override void Start(IEnumerable<ITest> selectedTests)
@ -67,7 +67,7 @@ namespace ICSharpCode.UnitTesting
void Start(ProcessStartInfo startInfo) void Start(ProcessStartInfo startInfo)
{ {
testResultsMonitor.Start(); testResultsReader.Start();
StartDebugger(startInfo); StartDebugger(startInfo);
} }
@ -90,6 +90,7 @@ namespace ICSharpCode.UnitTesting
void DebugStopped(object source, EventArgs e) void DebugStopped(object source, EventArgs e)
{ {
debugger.DebugStopped -= DebugStopped; debugger.DebugStopped -= DebugStopped;
testResultsReader.Join();
OnAllTestsFinished(source, e); OnAllTestsFinished(source, e);
} }
@ -98,15 +99,12 @@ namespace ICSharpCode.UnitTesting
if (debugger.IsDebugging) { if (debugger.IsDebugging) {
debugger.Stop(); debugger.Stop();
} }
testResultsMonitor.Stop();
testResultsMonitor.Read();
} }
public override void Dispose() public override void Dispose()
{ {
Stop(); testResultsReader.Dispose();
testResultsMonitor.Dispose(); testResultsReader.TestFinished -= OnTestFinished;
} }
} }
} }

28
src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBase.cs

@ -11,17 +11,17 @@ using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting namespace ICSharpCode.UnitTesting
{ {
public class TestProcessRunnerBase : TestRunnerBase public abstract class TestProcessRunnerBase : TestRunnerBase
{ {
IUnitTestProcessRunner processRunner; IUnitTestProcessRunner processRunner;
ITestResultsMonitor testResultsMonitor; ITestResultsReader testResultsReader;
IFileSystem fileSystem; IFileSystem fileSystem;
IMessageService messageService; IMessageService messageService;
public TestProcessRunnerBase(TestProcessRunnerBaseContext context) public TestProcessRunnerBase(TestProcessRunnerBaseContext context)
{ {
this.processRunner = context.TestProcessRunner; this.processRunner = context.TestProcessRunner;
this.testResultsMonitor = context.TestResultsMonitor; this.testResultsReader = context.TestResultsReader;
this.fileSystem = context.FileSystem; this.fileSystem = context.FileSystem;
this.messageService = context.MessageService; this.messageService = context.MessageService;
@ -29,11 +29,11 @@ namespace ICSharpCode.UnitTesting
processRunner.OutputLineReceived += OutputLineReceived; processRunner.OutputLineReceived += OutputLineReceived;
processRunner.ErrorLineReceived += OutputLineReceived; processRunner.ErrorLineReceived += OutputLineReceived;
processRunner.ProcessExited += OnAllTestsFinished; processRunner.ProcessExited += OnAllTestsFinished;
testResultsMonitor.TestFinished += OnTestFinished; testResultsReader.TestFinished += OnTestFinished;
} }
protected ITestResultsMonitor TestResultsMonitor { protected ITestResultsReader TestResultsReader {
get { return testResultsMonitor; } get { return testResultsReader; }
} }
protected IUnitTestProcessRunner ProcessRunner { protected IUnitTestProcessRunner ProcessRunner {
@ -56,7 +56,7 @@ namespace ICSharpCode.UnitTesting
LogCommandLine(processStartInfo); LogCommandLine(processStartInfo);
if (ApplicationFileNameExists(processStartInfo.FileName)) { if (ApplicationFileNameExists(processStartInfo.FileName)) {
testResultsMonitor.Start(); testResultsReader.Start();
processRunner.WorkingDirectory = processStartInfo.WorkingDirectory; processRunner.WorkingDirectory = processStartInfo.WorkingDirectory;
processRunner.Start(processStartInfo.FileName, processStartInfo.Arguments); processRunner.Start(processStartInfo.FileName, processStartInfo.Arguments);
} else { } else {
@ -75,17 +75,23 @@ namespace ICSharpCode.UnitTesting
messageService.ShowErrorFormatted(resourceString, fileName); messageService.ShowErrorFormatted(resourceString, fileName);
} }
protected override void OnAllTestsFinished(object source, EventArgs e)
{
testResultsReader.Join();
base.OnAllTestsFinished(source, e);
}
public override void Stop() public override void Stop()
{ {
SD.Log.Info("Killing unit test runner");
processRunner.Kill(); processRunner.Kill();
testResultsMonitor.Stop();
testResultsMonitor.Read();
} }
public override void Dispose() public override void Dispose()
{ {
testResultsMonitor.Dispose(); processRunner.Dispose();
testResultsMonitor.TestFinished -= OnTestFinished; testResultsReader.Dispose();
testResultsReader.TestFinished -= OnTestFinished;
processRunner.ErrorLineReceived -= OutputLineReceived; processRunner.ErrorLineReceived -= OutputLineReceived;
processRunner.OutputLineReceived -= OutputLineReceived; processRunner.OutputLineReceived -= OutputLineReceived;
} }

12
src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBaseContext.cs

@ -11,25 +11,25 @@ namespace ICSharpCode.UnitTesting
public class TestProcessRunnerBaseContext public class TestProcessRunnerBaseContext
{ {
IUnitTestProcessRunner processRunner; IUnitTestProcessRunner processRunner;
ITestResultsMonitor testResultsMonitor; ITestResultsReader testResultsReader;
IFileSystem fileSystem; IFileSystem fileSystem;
IMessageService messageService; IMessageService messageService;
public TestProcessRunnerBaseContext() public TestProcessRunnerBaseContext()
: this(new UnitTestProcessRunner(), : this(new UnitTestProcessRunner(),
new TestResultsMonitor(), new TestResultsReader(),
new UnitTestFileService(), new UnitTestFileService(),
SD.MessageService) SD.MessageService)
{ {
} }
public TestProcessRunnerBaseContext(IUnitTestProcessRunner processRunner, public TestProcessRunnerBaseContext(IUnitTestProcessRunner processRunner,
ITestResultsMonitor testResultsMonitor, ITestResultsReader testResultsMonitor,
IFileSystem fileSystem, IFileSystem fileSystem,
IMessageService messageService) IMessageService messageService)
{ {
this.processRunner = processRunner; this.processRunner = processRunner;
this.testResultsMonitor = testResultsMonitor; this.testResultsReader = testResultsMonitor;
this.fileSystem = fileSystem; this.fileSystem = fileSystem;
this.messageService = messageService; this.messageService = messageService;
} }
@ -38,8 +38,8 @@ namespace ICSharpCode.UnitTesting
get { return processRunner; } get { return processRunner; }
} }
public ITestResultsMonitor TestResultsMonitor { public ITestResultsReader TestResultsReader {
get { return testResultsMonitor; } get { return testResultsReader; }
} }
public IFileSystem FileSystem { public IFileSystem FileSystem {

178
src/AddIns/Analysis/UnitTesting/TestRunner/TestResultsMonitor.cs

@ -1,178 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using System.Text;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Watches for new test results as they occur. Test results
/// are written to a file and read in by this class.
/// </summary>
public class TestResultsMonitor : ITestResultsMonitor
{
FileInfo fileInfo;
TestResultsReader testResultsReader;
FileSystemWatcher fileSystemWatcher;
long initialFilePosition = 3;
long filePosition;
const int BytesBufferLength = 1024;
byte[] bytes = new byte[BytesBufferLength];
/// <summary>
/// Raised when a single test has been completed.
/// </summary>
public event EventHandler<TestFinishedEventArgs> TestFinished;
public TestResultsMonitor(string fileName)
{
fileInfo = new FileInfo(fileName);
ResetFilePosition();
}
public TestResultsMonitor()
: this(Path.GetTempFileName())
{
ResetFilePosition();
}
public long InitialFilePosition {
get { return initialFilePosition; }
set { initialFilePosition = value; }
}
/// <summary>
/// Gets or sets the test results filename.
/// </summary>
public string FileName {
get { return fileInfo.FullName; }
set { fileInfo = new FileInfo(value); }
}
/// <summary>
/// Starts monitoring for test results.
/// </summary>
public void Start()
{
testResultsReader = new TestResultsReader();
ResetFilePosition();
string filter = fileInfo.Name;
fileSystemWatcher = new FileSystemWatcher(fileInfo.DirectoryName, filter);
if (File.Exists(fileInfo.FullName)) {
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Changed += FileChanged;
} else {
fileSystemWatcher.Created += FileCreated;
}
fileSystemWatcher.Error += FileSystemWatcherError;
fileSystemWatcher.EnableRaisingEvents = true;
}
/// <summary>
/// Stops monitoring.
/// </summary>
public void Stop()
{
if (fileSystemWatcher != null) {
fileSystemWatcher.Dispose();
fileSystemWatcher = null;
}
}
/// <summary>
/// Reads the rest of the file from the current position.
/// Raises the TestFinished event for each test result
/// still in the file.
/// </summary>
public void Read()
{
string text = ReadTextAdded();
if (text != null) {
TestResult[] results = testResultsReader.Read(text);
OnTestResultsReceived(results);
}
}
/// <summary>
/// Stops monitoring and releases any resources used
/// by the TestResultsMonitor.
/// </summary>
public void Dispose()
{
Stop();
try {
File.Delete(FileName);
} catch { }
}
void FileCreated(object source, FileSystemEventArgs e)
{
fileSystemWatcher.Created -= FileCreated;
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Changed += FileChanged;
}
void FileChanged(object source, FileSystemEventArgs e)
{
Read();
}
void OnTestResultsReceived(TestResult[] results)
{
if ((results.Length > 0) && (TestFinished != null)) {
foreach (TestResult result in results) {
TestFinished(this, new TestFinishedEventArgs(result));
}
}
}
/// <summary>
/// Reads the text added to the end of the file from the last
/// position we read from.
/// </summary>
string ReadTextAdded()
{
StringBuilder text = null;
try {
using (FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
if (fs.Length > 0) {
text = new StringBuilder();
int bytesRead = 0;
fs.Seek(filePosition, SeekOrigin.Begin);
do {
bytesRead = fs.Read(bytes, 0, BytesBufferLength);
if (bytesRead > 0) {
filePosition += bytesRead;
text.Append(UTF8Encoding.UTF8.GetString(bytes, 0, bytesRead));
}
} while ((bytesRead > 0) && (filePosition < fs.Length));
}
}
} catch (FileNotFoundException) {
// Test was aborted before it even started execution
return null;
}
if (text != null) {
return text.ToString();
}
return null;
}
void FileSystemWatcherError(object source, ErrorEventArgs e)
{
Console.WriteLine(e.GetException().ToString());
}
void ResetFilePosition()
{
filePosition = initialFilePosition;
}
}
}

122
src/AddIns/Analysis/UnitTesting/TestRunner/TestResultsReader.cs

@ -2,52 +2,118 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.Collections.Generic; using System.IO;
using System.IO.Pipes;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.UnitTesting namespace ICSharpCode.UnitTesting
{ {
/// <summary> public interface ITestResultsReader : IDisposable
/// Reads the test results file produced by the custom
/// nunit-console application.
/// </summary>
public class TestResultsReader
{ {
StringBuilder nameBuilder = new StringBuilder(); event EventHandler<TestFinishedEventArgs> TestFinished;
StringBuilder valueBuilder = new StringBuilder(); string PipeName { get; }
bool firstNameChar = true; void Start();
TestResult result; void Join();
}
public class TestResultsReader : ITestResultsReader
{
TextReader reader;
readonly NamedPipeServerStream namedPipe;
readonly string pipeName;
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
enum State { public TestResultsReader()
WaitingForEndOfName = 0, {
WaitingForStartOfValue = 1, pipeName = Guid.NewGuid().ToString();
WaitingForEndOfValue = 2 namedPipe = new NamedPipeServerStream(this.PipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte);
} }
State state = State.WaitingForEndOfName; /// <summary>
/// Creates a new TestResultsReader that reads from an existing text reader.
/// </summary>
public TestResultsReader(TextReader reader)
{
this.reader = reader;
}
public TestResultsReader() public string PipeName {
get { return pipeName; }
}
public void Dispose()
{
reader.Dispose();
namedPipe.Dispose();
}
public event EventHandler<TestFinishedEventArgs> TestFinished;
Thread thread;
/// <summary>
/// Runs the pipe reader on a background thread.
/// The returned task will be signalled as completed when the worker process closes the pipe, after
/// all contents have been read from the pipe.
/// </summary>
public void Start()
{ {
thread = new Thread(Run);
thread.Name = "UnitTesting Pipe Reader";
thread.Start();
}
public void Join()
{
SD.Log.Debug("Waiting for pipe reader to finish");
thread.Join();
SD.Log.Debug("Pipe reader has finished");
} }
/// <summary> /// <summary>
/// Returns any TestResults that are in the text. /// Run the pipe reader on the current thread.
/// This method blocks until the worker process closes the pipe.
/// </summary> /// </summary>
/// <param name="text">The text read in from the public void Run()
/// TestResults file.</param>
public TestResult[] Read(string text)
{ {
List<TestResult> results = new List<TestResult>(); if (reader == null) {
foreach (char ch in text) { SD.Log.Debug("Waiting for connection to pipe");
if (ReadNameValuePair(ch)) { namedPipe.WaitForConnection();
if (ReadTestResult()) { SD.Log.Debug("Start reading pipe");
results.Add(result); reader = new StreamReader(namedPipe);
}
char[] buffer = new char[1024];
int read;
while ((read = reader.Read(buffer, 0, buffer.Length)) != 0) {
for (int i = 0; i < read; i++) {
if (ReadNameValuePair(buffer[i])) {
if (ReadTestResult()) {
if (TestFinished != null)
TestFinished(this, new TestFinishedEventArgs(result));
}
} }
} }
} }
return results.ToArray(); SD.Log.Debug("End of pipe");
}
StringBuilder nameBuilder = new StringBuilder();
StringBuilder valueBuilder = new StringBuilder();
bool firstNameChar = true;
TestResult result;
enum State {
WaitingForEndOfName = 0,
WaitingForStartOfValue = 1,
WaitingForEndOfValue = 2
} }
State state = State.WaitingForEndOfName;
/// <summary> /// <summary>
/// Reads a name-value pair of the form: /// Reads a name-value pair of the form:
/// ///
@ -119,8 +185,8 @@ namespace ICSharpCode.UnitTesting
/// <returns>True if a TestResult is ready to be returned /// <returns>True if a TestResult is ready to be returned
/// to the caller.</returns> /// to the caller.</returns>
/// <remarks> /// <remarks>
/// The first name-value pair for a test result is the /// The first name-value pair for a test result is the
/// test name. The last name-value pair is the result of /// test name. The last name-value pair is the result of
/// the test (Success, Failure or Ignored).</remarks> /// the test (Success, Failure or Ignored).</remarks>
bool ReadTestResult() bool ReadTestResult()
{ {

11
src/AddIns/Analysis/UnitTesting/TestRunner/TestRunnerBase.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -11,12 +12,17 @@ namespace ICSharpCode.UnitTesting
{ {
public abstract class TestRunnerBase : ITestRunner public abstract class TestRunnerBase : ITestRunner
{ {
IProgress<double> progress;
double progressPerTest;
int testsFinished;
TaskCompletionSource<object> tcs; TaskCompletionSource<object> tcs;
CancellationTokenRegistration cancellationTokenRegistration; CancellationTokenRegistration cancellationTokenRegistration;
bool wasCancelled; bool wasCancelled;
public Task RunAsync(IEnumerable<ITest> selectedTests, IProgress<double> progress, CancellationToken cancellationToken) public Task RunAsync(IEnumerable<ITest> selectedTests, IProgress<double> progress, CancellationToken cancellationToken)
{ {
this.progress = progress;
progressPerTest = 1.0 / GetExpectedNumberOfTestResults(selectedTests);
tcs = new TaskCompletionSource<object>(); tcs = new TaskCompletionSource<object>();
Start(selectedTests); Start(selectedTests);
cancellationTokenRegistration = cancellationToken.Register(Cancel, true); cancellationTokenRegistration = cancellationToken.Register(Cancel, true);
@ -45,7 +51,7 @@ namespace ICSharpCode.UnitTesting
return String.Format("\"{0}\" {1}", startInfo.FileName, startInfo.Arguments); return String.Format("\"{0}\" {1}", startInfo.FileName, startInfo.Arguments);
} }
protected void OnAllTestsFinished(object source, EventArgs e) protected virtual void OnAllTestsFinished(object source, EventArgs e)
{ {
cancellationTokenRegistration.Dispose(); cancellationTokenRegistration.Dispose();
if (wasCancelled) if (wasCancelled)
@ -62,6 +68,8 @@ namespace ICSharpCode.UnitTesting
TestResult testResult = CreateTestResultForTestFramework(e.Result); TestResult testResult = CreateTestResultForTestFramework(e.Result);
TestFinished(source, new TestFinishedEventArgs(testResult)); TestFinished(source, new TestFinishedEventArgs(testResult));
} }
if (!double.IsInfinity(progressPerTest))
progress.Report(progressPerTest * Interlocked.Increment(ref testsFinished));
} }
protected virtual TestResult CreateTestResultForTestFramework(TestResult testResult) protected virtual TestResult CreateTestResultForTestFramework(TestResult testResult)
@ -78,6 +86,7 @@ namespace ICSharpCode.UnitTesting
} }
} }
public abstract int GetExpectedNumberOfTestResults(IEnumerable<ITest> selectedTests);
public abstract void Dispose(); public abstract void Dispose();
public abstract void Stop(); public abstract void Stop();
public abstract void Start(IEnumerable<ITest> selectedTests); public abstract void Start(IEnumerable<ITest> selectedTests);

4
src/AddIns/Analysis/UnitTesting/UnitTesting.csproj

@ -107,17 +107,15 @@
<Compile Include="Service\TestFrameworkDescriptor.cs" /> <Compile Include="Service\TestFrameworkDescriptor.cs" />
<Compile Include="Service\TestFrameworkDoozer.cs" /> <Compile Include="Service\TestFrameworkDoozer.cs" />
<Compile Include="Service\SDTestService.cs" /> <Compile Include="Service\SDTestService.cs" />
<Compile Include="TestRunner\ITestResultsMonitor.cs" />
<Compile Include="TestRunner\ITestRunner.cs" /> <Compile Include="TestRunner\ITestRunner.cs" />
<Compile Include="TestRunner\MessageReceivedEventArgs.cs" /> <Compile Include="TestRunner\MessageReceivedEventArgs.cs" />
<Compile Include="TestRunner\TestDebuggerBase.cs" /> <Compile Include="TestRunner\TestDebuggerBase.cs" />
<Compile Include="TestRunner\TestExecutionManager.cs" /> <Compile Include="TestRunner\TestExecutionManager.cs" />
<Compile Include="TestRunner\TestExecutionOptions.cs" /> <Compile Include="TestRunner\TestExecutionOptions.cs" />
<Compile Include="TestRunner\TestFinishedEventArgs.cs" /> <Compile Include="TestRunner\TestFinishedEventArgs.cs" />
<Compile Include="TestRunner\TestResultsReader.cs" />
<Compile Include="TestRunner\TestProcessRunnerBase.cs" /> <Compile Include="TestRunner\TestProcessRunnerBase.cs" />
<Compile Include="TestRunner\TestProcessRunnerBaseContext.cs" /> <Compile Include="TestRunner\TestProcessRunnerBaseContext.cs" />
<Compile Include="TestRunner\TestResultsMonitor.cs" />
<Compile Include="TestRunner\TestResultsReader.cs" />
<Compile Include="TestRunner\TestResultTask.cs" /> <Compile Include="TestRunner\TestResultTask.cs" />
<Compile Include="TestRunner\TestRunnerBase.cs" /> <Compile Include="TestRunner\TestRunnerBase.cs" />
<Compile Include="NUnit\NUnitConsoleApplication.cs" /> <Compile Include="NUnit\NUnitConsoleApplication.cs" />

23
src/Main/Base/Project/Src/Util/ProcessRunner.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.SharpDevelop.Util
Process process; Process process;
StringBuilder standardOutput = new StringBuilder(); StringBuilder standardOutput = new StringBuilder();
StringBuilder standardError = new StringBuilder(); StringBuilder standardError = new StringBuilder();
ManualResetEvent endOfOutput = new ManualResetEvent(false); ManualResetEventSlim endOfOutput = new ManualResetEventSlim(false);
int outputStreamsFinished; int outputStreamsFinished;
/// <summary> /// <summary>
@ -91,7 +91,7 @@ namespace ICSharpCode.SharpDevelop.Util
public void Dispose() public void Dispose()
{ {
process.Dispose(); process.Dispose();
endOfOutput.Close(); endOfOutput.Dispose();
} }
/// <summary> /// <summary>
@ -130,7 +130,7 @@ namespace ICSharpCode.SharpDevelop.Util
bool exited = process.WaitForExit(timeout); bool exited = process.WaitForExit(timeout);
if (exited) { if (exited) {
endOfOutput.WaitOne(timeout == int.MaxValue ? Timeout.Infinite : timeout, false); endOfOutput.Wait(timeout == int.MaxValue ? Timeout.Infinite : timeout);
} }
return exited; return exited;
@ -216,14 +216,15 @@ namespace ICSharpCode.SharpDevelop.Util
{ {
if (process != null) { if (process != null) {
if (!process.HasExited) { if (!process.HasExited) {
process.Kill(); try {
process.Close(); process.Kill();
process.Dispose(); } catch (InvalidOperationException) {
process = null; // race condition (if the process has already exited)
endOfOutput.WaitOne(); }
} else { // don't call process.Dispose() here - that causes the OnProcessExited
process = null; // event not to fire correctly
} }
endOfOutput.Wait();
} }
} }
@ -234,7 +235,7 @@ namespace ICSharpCode.SharpDevelop.Util
{ {
if (ProcessExited != null) { if (ProcessExited != null) {
if (endOfOutput != null) { if (endOfOutput != null) {
endOfOutput.WaitOne(); endOfOutput.Wait();
} }
ProcessExited(this, e); ProcessExited(this, e);

2
src/Tools/NUnit/buildnunitconsole.bat

@ -1,6 +1,6 @@
%windir%\microsoft.net\framework\v4.0.30319\msbuild /Target:Rebuild /property:Configuration=Release nunit-console\nunit-console.sln %windir%\microsoft.net\framework\v4.0.30319\msbuild /Target:Rebuild /property:Configuration=Release nunit-console\nunit-console.sln
copy nunit-console.exe nunit-console-x86.exe copy nunit-console.exe nunit-console-x86.exe
corflags /32bit+ nunit-console-x86.exe "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\corflags" /32bit+ nunit-console-x86.exe
@IF %ERRORLEVEL% NEQ 0 GOTO err @IF %ERRORLEVEL% NEQ 0 GOTO err
copy nunit-console.exe nunit-console-dotnet2.exe copy nunit-console.exe nunit-console-dotnet2.exe
copy nunit-console-x86.exe nunit-console-dotnet2-x86.exe copy nunit-console-x86.exe nunit-console-dotnet2-x86.exe

BIN
src/Tools/NUnit/nunit-console-dotnet2-x86.exe

Binary file not shown.

BIN
src/Tools/NUnit/nunit-console-dotnet2.exe

Binary file not shown.

BIN
src/Tools/NUnit/nunit-console-x86.exe

Binary file not shown.

BIN
src/Tools/NUnit/nunit-console.exe

Binary file not shown.

8
src/Tools/NUnit/nunit-console/ExtendedConsoleOptions.cs

@ -14,14 +14,14 @@ namespace NUnit.ConsoleRunner
{ {
public ExtendedConsoleOptions(string[] args) : base(args) {} public ExtendedConsoleOptions(string[] args) : base(args) {}
[Option(Description="File to receive test results as each test is run")] [Option(Description="Named pipe to receive test results as each test is run")]
public string results; public string pipe;
public bool IsResults public bool UsePipe
{ {
get get
{ {
return (results != null) && (results.Length != 0); return !string.IsNullOrEmpty(pipe);
} }
} }
} }

9
src/Tools/NUnit/nunit-console/ExtendedConsoleUi.cs

@ -1,3 +1,4 @@
using System.IO.Pipes;
// **************************************************************** // ****************************************************************
// This is free software licensed under the NUnit license. You // This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding // may obtain a copy of the license as well as information regarding
@ -64,9 +65,11 @@ namespace NUnit.ConsoleRunner
} }
TextWriter testResultWriter = null; TextWriter testResultWriter = null;
if ( options.IsResults ) if ( options.UsePipe )
{ {
testResultWriter = new StreamWriter ( options.results, false, Encoding.UTF8 ); var namedPipe = new NamedPipeClientStream(".", options.pipe, PipeDirection.Out, PipeOptions.WriteThrough);
namedPipe.Connect();
testResultWriter = new StreamWriter ( namedPipe, Encoding.UTF8 );
((StreamWriter)testResultWriter).AutoFlush = true; ((StreamWriter)testResultWriter).AutoFlush = true;
} }
TestPackage package = MakeTestPackage(options); TestPackage package = MakeTestPackage(options);
@ -184,7 +187,7 @@ namespace NUnit.ConsoleRunner
outWriter.Close(); outWriter.Close();
if ( redirectError ) if ( redirectError )
errorWriter.Close(); errorWriter.Close();
if ( options.IsResults ) if ( testResultWriter != null )
testResultWriter.Close(); testResultWriter.Close();
Environment.CurrentDirectory = savedDirectory; Environment.CurrentDirectory = savedDirectory;

8
src/Tools/NUnit/nunit-console/nunit-console.csproj

@ -1,4 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>NUnit.ConsoleRunner</RootNamespace> <RootNamespace>NUnit.ConsoleRunner</RootNamespace>
@ -14,7 +15,7 @@
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<ApplicationIcon>App.ico</ApplicationIcon> <ApplicationIcon>App.ico</ApplicationIcon>
<SourceAnalysisOverrideSettingsFile>C:\Users\matt\AppData\Roaming\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis</SourceAnalysisOverrideSettingsFile> <SourceAnalysisOverrideSettingsFile>C:\Users\matt\AppData\Roaming\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis</SourceAnalysisOverrideSettingsFile>
</PropertyGroup> </PropertyGroup>
@ -54,6 +55,9 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />

Loading…
Cancel
Save