diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..e9ea482
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,42 @@
+# EditorConfig helps developers define and
+# maintain consistent coding styles between
+# different editors and IDEs
+
+# http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = crlf
+# Make selection with keyboard easier in all files
+insert_final_newline = true
+
+[*.proj]
+indent_size = 2
+
+[*.csproj]
+indent_size = 2
+
+[*.vcxproj]
+indent_size = 2
+
+[*.xproj]
+indent_size = 2
+
+[*.json]
+indent_size = 2
+
+[*.config]
+indent_size = 2
+
+[*.nuspec]
+indent_size = 2
+
+[*.xml]
+indent_size = 2
+
+[*.cs]
+csharp_new_line_before_open_brace = all
diff --git a/CHANGES.txt b/CHANGES.txt
index 0cb20ec..88edec6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,12 @@
+VS Project Loader Extension 3.7 - August 6, 2017
+
+ Added support for new file format for .NET Core csproj files. Added .editorconfig for
+ consistency with main NUnit project.
+
+ Issues Resolved
+
+ * 11 Invalid Project Format Exception if Project is new project file format
+
VS Project Loader Extension 3.6 - August 1, 2017
Fixes several packaging errors and adds a new chocolatey package. Runners and engines
diff --git a/src/extension/VSProject.cs b/src/extension/VSProject.cs
index 3c236a7..2393e5c 100644
--- a/src/extension/VSProject.cs
+++ b/src/extension/VSProject.cs
@@ -187,17 +187,23 @@ private void Load()
ThrowInvalidFileType( ProjectPath );
StreamReader rdr = new StreamReader(ProjectPath, System.Text.Encoding.UTF8);
-
+
try
{
_doc = new XmlDocument();
- _doc.Load( rdr );
+ _doc.Load(rdr);
- string extension = Path.GetExtension( ProjectPath );
+ string extension = Path.GetExtension(ProjectPath);
- switch ( extension )
+ switch (extension)
{
case ".csproj":
+ // We try legacy project first, then new format for .NET Core projects
+ if (!TryLoadLegacyProject())
+ if (!TryLoadDotNetCoreProject())
+ LoadMSBuildProject();
+ break;
+
case ".vbproj":
case ".vjsproj":
case ".fsproj":
@@ -228,6 +234,74 @@ private void Load()
}
}
+ ///
+ /// Load a project in the new project format for .NET Core 1.0/1.1. Note that this method
+ /// is only called for file extensions .csproj.
+ ///
+ /// True if the project was successfully loaded, false otherwise.
+ private bool TryLoadDotNetCoreProject() {
+ XmlNode root = _doc.SelectSingleNode("Project");
+
+ if (root != null && SafeAttributeValue(root, "Sdk") != null)
+ {
+ string targetFramework = _doc.SelectSingleNode("Project/PropertyGroup/TargetFramework").InnerText;
+
+ XmlNode assemblyNameNode = _doc.SelectSingleNode("Project/PropertyGroup/AssemblyName");
+ // Even console apps are dll's even if has value 'EXE'
+ string assemblyName = assemblyNameNode == null ? $"{Name}.dll" : $"{assemblyNameNode.InnerText}.dll";
+
+ XmlNodeList nodes = _doc.SelectNodes("/Project/PropertyGroup");
+
+ string commonOutputPath = null;
+
+ foreach (XmlElement configNode in nodes)
+ {
+ string configName = GetConfigNameFromCondition(configNode);
+
+ XmlElement outputPathElement = (XmlElement)configNode.SelectSingleNode("OutputPath");
+ string outputPath = null;
+ if (outputPathElement != null)
+ outputPath = outputPathElement.InnerText;
+
+ if (configName == null)
+ {
+ commonOutputPath = outputPath;
+ continue;
+ }
+
+ if (outputPath == null)
+ outputPath = commonOutputPath;
+
+ if (outputPath != null)
+ _configs.Add(configName, new ProjectConfig(this, configName, outputPath, assemblyName));
+ }
+
+ // By convention there is a Debug and a Release configuration unless others are explicitly
+ // mentioned in the project file. If we have less than 2 then at least one of those is missing.
+ // We cannot tell however if the existing configuration is meant to replace Debug or Release.
+ // Therefore we just add what is missing. The one that has been replaced will not be used.
+ if (_configs.Count < 2)
+ {
+ if (!_configs.ContainsKey("Debug"))
+ {
+ string configName = "Debug";
+ string outputPath = $@"bin\{configName}\{targetFramework}";
+ _configs.Add(configName, new ProjectConfig(this, configName, outputPath, assemblyName));
+ }
+ if (!_configs.ContainsKey("Release"))
+ {
+ string configName = "Release";
+ string outputPath = $@"bin\{configName}\{targetFramework}";
+ _configs.Add(configName, new ProjectConfig(this, configName, outputPath, assemblyName));
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
///
/// Load a project in the legacy VS2003 format. Note that this method is not
/// called for C++ projects using the same format, because the details differ.
diff --git a/src/tests/VisualStudioProjectLoaderTests.cs b/src/tests/VisualStudioProjectLoaderTests.cs
index aba199a..091c8fa 100644
--- a/src/tests/VisualStudioProjectLoaderTests.cs
+++ b/src/tests/VisualStudioProjectLoaderTests.cs
@@ -23,6 +23,7 @@
using System;
using System.IO;
+using System.Linq;
using NUnit.Engine.Extensibility;
using NUnit.Engine.Tests.resources;
using NUnit.Framework;
@@ -119,6 +120,7 @@ public void CannotLoadWebProject()
[TestCase("legacy-cpp-sample.vcproj", new string[] { "Debug|Win32", "Release|Win32" }, "cpp-sample")]
[TestCase("legacy-cpp-library-with-macros.vcproj", new string[] { "Debug|Win32", "Release|Win32" }, "legacy-cpp-library-with-macros")]
[TestCase("legacy-cpp-makefile-project.vcproj", new string[] { "Debug|Win32", "Release|Win32" }, "MakeFileProject")]
+ [TestCase("netcoreapp1.1-minimal.csproj", new string[] { "Debug", "Release" }, "netcoreapp1.1-minimal")]
public void CanLoadVsProject(string resourceName, string[] configs, string assemblyName)
{
Assert.That(_loader.CanLoadFrom(resourceName));
@@ -142,6 +144,40 @@ public void CanLoadVsProject(string resourceName, string[] configs, string assem
}
}
+ [TestCase("netcoreapp1.1-minimal.csproj", "Debug", @"bin/Debug/netcoreapp1.1")]
+ [TestCase("netcoreapp1.1-minimal.csproj", "Release", @"bin/Release/netcoreapp1.1")]
+ [TestCase("netcoreapp1.1-with-output-path.csproj", "Debug", @"bin/Debug/netcoreapp1.1")]
+ [TestCase("netcoreapp1.1-with-output-path.csproj", "Release", @"bin/Release/special")]
+ public void PicksUpCorrectOutputPath(string resourceName, string configuration, string expectedOutputPath)
+ {
+ using (TestResource file = new TestResource(resourceName))
+ {
+ IProject project = _loader.LoadFrom(file.Path);
+
+ var package = project.GetTestPackage(configuration);
+ // adjust for difference between Linux/Win:
+ var basePath = package.Settings["BasePath"].ToString().Replace('\\', '/');
+ Assert.That(basePath.EndsWith(expectedOutputPath));
+ }
+ }
+
+ [TestCase("netcoreapp1.1-minimal.csproj", "netcoreapp1.1-minimal")]
+ [TestCase("netcoreapp1.1-with-assembly-name.csproj", "the-assembly-name")]
+ public void PicksUpCorrectAssemplyName(string resouresName, string expectedAssemblyName)
+ {
+ using (TestResource file = new TestResource(resouresName))
+ {
+ IProject project = _loader.LoadFrom(file.Path);
+
+ foreach(var config in project.ConfigNames)
+ {
+ TestPackage package = project.GetTestPackage(config);
+
+ Assert.That(Path.GetFileNameWithoutExtension(package.SubPackages[0].FullName) == expectedAssemblyName);
+ }
+ }
+ }
+
[Test]
public void FromVSSolution2003()
{
diff --git a/src/tests/resources/netcoreapp1.1-minimal.csproj b/src/tests/resources/netcoreapp1.1-minimal.csproj
new file mode 100644
index 0000000..abb9969
--- /dev/null
+++ b/src/tests/resources/netcoreapp1.1-minimal.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ netcoreapp1.1
+
+
+
diff --git a/src/tests/resources/netcoreapp1.1-with-assembly-name.csproj b/src/tests/resources/netcoreapp1.1-with-assembly-name.csproj
new file mode 100644
index 0000000..90024a0
--- /dev/null
+++ b/src/tests/resources/netcoreapp1.1-with-assembly-name.csproj
@@ -0,0 +1,9 @@
+
+
+
+ Exe
+ netcoreapp1.1
+ the-assembly-name
+
+
+
\ No newline at end of file
diff --git a/src/tests/resources/netcoreapp1.1-with-output-path.csproj b/src/tests/resources/netcoreapp1.1-with-output-path.csproj
new file mode 100644
index 0000000..d02a2a7
--- /dev/null
+++ b/src/tests/resources/netcoreapp1.1-with-output-path.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp1.1
+
+
+
+ bin\Release\special
+
+
+
\ No newline at end of file
diff --git a/src/tests/vs-project-loader.tests.csproj b/src/tests/vs-project-loader.tests.csproj
index 425eb83..4d5b25a 100644
--- a/src/tests/vs-project-loader.tests.csproj
+++ b/src/tests/vs-project-loader.tests.csproj
@@ -97,6 +97,15 @@
+
+
+
+
+
+
+
+
+