diff --git a/src/Unosquare.Swan/Components/CsProjFile.cs b/src/Unosquare.Swan/Components/CsProjFile.cs
new file mode 100644
index 000000000..3bd550cb6
--- /dev/null
+++ b/src/Unosquare.Swan/Components/CsProjFile.cs
@@ -0,0 +1,100 @@
+namespace Unosquare.Swan.Components
+{
+ using System;
+ using System.IO;
+ using System.Linq;
+ using System.Xml.Linq;
+
+ ///
+ /// Represents a CsProjFile parser
+ /// Based on https://github.com/maartenba/dotnetcli-init
+ ///
+ /// The type of CsProjMetadataBase
+ ///
+ public class CsProjFile
+ : IDisposable
+ where T : CsProjMetadataBase
+ {
+ private readonly Stream _stream;
+ private readonly bool _leaveOpen;
+ private readonly XDocument _xmlDocument;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The filename.
+ public CsProjFile(string filename = null)
+ : this(OpenFile(filename))
+ {
+ // placeholder
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The stream.
+ /// if set to true [leave open].
+ /// Project file is not of the new .csproj type.
+ public CsProjFile(Stream stream, bool leaveOpen = false)
+ {
+ _stream = stream;
+ _leaveOpen = leaveOpen;
+
+ _xmlDocument = XDocument.Load(stream);
+
+ var projectElement = _xmlDocument.Descendants("Project").FirstOrDefault();
+ if (projectElement == null || projectElement.Attribute("Sdk")?.Value != "Microsoft.NET.Sdk")
+ {
+ throw new ArgumentException("Project file is not of the new .csproj type.");
+ }
+
+ Metadata = Activator.CreateInstance();
+ Metadata.SetData(_xmlDocument);
+ }
+
+ ///
+ /// Gets the metadata.
+ ///
+ ///
+ /// The nu get metadata.
+ ///
+ public T Metadata { get; }
+
+ ///
+ /// Saves this instance.
+ ///
+ public void Save()
+ {
+ _stream.SetLength(0);
+ _stream.Position = 0;
+
+ _xmlDocument.Save(_stream);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ if (!_leaveOpen)
+ {
+ _stream?.Dispose();
+ }
+ }
+
+ private static FileStream OpenFile(string filename)
+ {
+ if (filename == null)
+ {
+ filename = Directory
+ .EnumerateFiles(Directory.GetCurrentDirectory(), "*.csproj", SearchOption.TopDirectoryOnly)
+ .FirstOrDefault();
+ }
+
+ if (string.IsNullOrWhiteSpace(filename))
+ throw new ArgumentNullException(nameof(filename));
+
+ return File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Unosquare.Swan/Components/CsProjMetadataBase.cs b/src/Unosquare.Swan/Components/CsProjMetadataBase.cs
new file mode 100644
index 000000000..334817cee
--- /dev/null
+++ b/src/Unosquare.Swan/Components/CsProjMetadataBase.cs
@@ -0,0 +1,79 @@
+namespace Unosquare.Swan.Components
+{
+ using System.Linq;
+ using System.Xml.Linq;
+
+ ///
+ /// Represents a CsProj metadata abstract class
+ /// to use with CsProjFile parser.
+ ///
+ public abstract class CsProjMetadataBase
+ {
+ private XDocument _xmlDocument;
+
+ ///
+ /// Gets the package identifier.
+ ///
+ ///
+ /// The package identifier.
+ ///
+ public string PackageId => FindElement(nameof(PackageId))?.Value;
+
+ ///
+ /// Gets the name of the assembly.
+ ///
+ ///
+ /// The name of the assembly.
+ ///
+ public string AssemblyName => FindElement(nameof(AssemblyName))?.Value;
+
+ ///
+ /// Gets the target frameworks.
+ ///
+ ///
+ /// The target frameworks.
+ ///
+ public string TargetFrameworks => FindElement(nameof(TargetFrameworks))?.Value;
+
+ ///
+ /// Gets the target framework.
+ ///
+ ///
+ /// The target framework.
+ ///
+ public string TargetFramework => FindElement(nameof(TargetFramework))?.Value;
+
+ ///
+ /// Gets the version.
+ ///
+ ///
+ /// The version.
+ ///
+ public string Version => FindElement(nameof(Version))?.Value;
+
+ ///
+ /// Parses the cs proj tags.
+ ///
+ /// The arguments.
+ public abstract void ParseCsProjTags(ref string[] args);
+
+ ///
+ /// Sets the data.
+ ///
+ /// The XML document.
+ public void SetData(XDocument xmlDocument)
+ {
+ _xmlDocument = xmlDocument;
+ }
+
+ ///
+ /// Finds the element.
+ ///
+ /// Name of the element.
+ /// A XElement.
+ protected XElement FindElement(string elementName)
+ {
+ return _xmlDocument.Descendants(elementName).FirstOrDefault();
+ }
+ }
+}
diff --git a/src/Unosquare.Swan/Unosquare.Swan.csproj b/src/Unosquare.Swan/Unosquare.Swan.csproj
index 9844d5996..2b535f09e 100644
--- a/src/Unosquare.Swan/Unosquare.Swan.csproj
+++ b/src/Unosquare.Swan/Unosquare.Swan.csproj
@@ -10,7 +10,7 @@
Unosquare.Swan
..\..\StyleCop.Analyzers.ruleset
Full
- 0.21.1
+ 0.22.0
Unosquare
https://github.com/unosquare/swan/raw/master/swan-logo-32.png
https://github.com/unosquare/swan
diff --git a/test/Unosquare.Swan.Test/CsProjFileTest.cs b/test/Unosquare.Swan.Test/CsProjFileTest.cs
new file mode 100644
index 000000000..9dd66cc6c
--- /dev/null
+++ b/test/Unosquare.Swan.Test/CsProjFileTest.cs
@@ -0,0 +1,101 @@
+namespace Unosquare.Swan.Test
+{
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using System.Xml;
+ using NUnit.Framework;
+ using Unosquare.Swan.Components;
+ using Unosquare.Swan.Test.Mocks;
+ using System;
+
+ public abstract class CsProjFileTest : TestFixtureBase
+ {
+ protected string _data = @"
+
+ Unit Testing project
+ Copyright(c) 2016-2017 - Unosquare
+ Unosquare SWAN Test
+ net46;netcoreapp2.0
+ Unosquare.Swan.Test
+ Full
+ ";
+ protected string _wrongSDK = @"";
+ }
+
+ [TestFixture]
+ public class CsProjFileConstructor : CsProjFileTest
+ {
+ [Test]
+ public void WithValidFileAndValidClass_ReturnsFileAndMetadata()
+ {
+ using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
+ using (var csproj = new CsProjFile(stream))
+ {
+ Assert.IsNotNull(csproj);
+ Assert.IsNotNull(csproj.Metadata);
+ Assert.IsNotNull(csproj.Metadata.Copyright);
+ }
+ }
+
+ [Test]
+ public void WithNullStream_ThrowsXmlException()
+ {
+ Assert.Throws(() =>
+ {
+ using (var stream = new MemoryStream())
+ using (var csproj = new CsProjFile(stream)) { }
+ });
+ }
+
+ [Test]
+ public void IfPropertyWasNotFound_ReturnsNull()
+ {
+ using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
+ using (var csproj = new CsProjFile(stream))
+ {
+ Assert.IsNull(csproj.Metadata.NonExistentProp);
+ }
+ }
+
+ [Test]
+ public void WithWrongSdk_ThrowsArgumentException()
+ {
+ Assert.Throws(() =>
+ {
+ using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_wrongSDK)))
+ using (var csproj = new CsProjFile(stream)){}
+ });
+ }
+
+ [Test]
+ public void WithAbstractClass_ThrowsMissingMethodException()
+ {
+ Assert.Throws(() =>
+ {
+ using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
+ using (var csproj = new CsProjFile(stream)) { }
+ });
+ }
+
+ [Test]
+ public void WithEmptyStringAsFileName_ThrowsArgumentNullException()
+ {
+ Assert.Throws(() =>
+ {
+ using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
+ using (var csproj = new CsProjFile(string.Empty)) { }
+ });
+ }
+
+ [Test]
+ public void WithNullAsFileName_ThrowsArgumentNullException()
+ {
+ Assert.Throws(() =>
+ {
+ using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
+ using (var csproj = new CsProjFile(null)) { }
+ });
+ }
+ }
+}
diff --git a/test/Unosquare.Swan.Test/ExtensionsDatesTest.cs b/test/Unosquare.Swan.Test/ExtensionsDatesTest.cs
index 5cec6acdd..4329eb28f 100644
--- a/test/Unosquare.Swan.Test/ExtensionsDatesTest.cs
+++ b/test/Unosquare.Swan.Test/ExtensionsDatesTest.cs
@@ -89,7 +89,7 @@ public class ToUnixEpochDate
[Test]
public void GivingADate_ConvertItIntoTicks()
{
- var date = new DateTime(2017, 10, 27);
+ var date = new DateTime(2017, 10, 27).ToUniversalTime().Date;
Assert.AreEqual(1509062400, date.ToUnixEpochDate());
}
diff --git a/test/Unosquare.Swan.Test/LdapTest.cs b/test/Unosquare.Swan.Test/LdapTest.cs
index 649b486d1..54a626838 100644
--- a/test/Unosquare.Swan.Test/LdapTest.cs
+++ b/test/Unosquare.Swan.Test/LdapTest.cs
@@ -183,17 +183,20 @@ public class ModifyTest : LdapTest
[Test]
public void ChangeUserProperty()
{
- var ex = Assert.ThrowsAsync(async () =>
+ var ex = Assert.CatchAsync(async () =>
{
var cn = await GetDefaultConnection();
await cn.Modify(
"uid=euclid,dc=example,dc=com",
- new[] { new LdapModification(LdapModificationOp.Replace, "mail", "new@ldap.forumsys.com")});
+ new[] {new LdapModification(LdapModificationOp.Replace, "mail", "new@ldap.forumsys.com")});
cn.Disconnect();
});
- Assert.AreEqual(ex.ResultCode, LdapStatusCode.InsufficientAccessRights);
+ if (ex is LdapException ldapEx)
+ Assert.AreEqual(ldapEx.ResultCode, LdapStatusCode.InsufficientAccessRights);
+ else
+ Assert.IsNotNull(ex);
}
}
diff --git a/test/Unosquare.Swan.Test/Mocks/CsProjFileMock.cs b/test/Unosquare.Swan.Test/Mocks/CsProjFileMock.cs
new file mode 100644
index 000000000..8eb0d087b
--- /dev/null
+++ b/test/Unosquare.Swan.Test/Mocks/CsProjFileMock.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Unosquare.Swan.Components;
+
+namespace Unosquare.Swan.Test.Mocks
+{
+ public class CsMetadataMock : CsProjMetadataBase
+ {
+ public string Copyright => FindElement(nameof(Copyright))?.Value;
+
+ public string NonExistentProp => FindElement(nameof(NonExistentProp))?.Value;
+
+ public override void ParseCsProjTags(ref string[] args)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public abstract class CsAbstractMetadataMock : CsProjMetadataBase
+ {
+ public override void ParseCsProjTags(ref string[] args)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/test/Unosquare.Swan.Test/Unosquare.Swan.Test.csproj b/test/Unosquare.Swan.Test/Unosquare.Swan.Test.csproj
index 33f05bd0c..c8843c260 100644
--- a/test/Unosquare.Swan.Test/Unosquare.Swan.Test.csproj
+++ b/test/Unosquare.Swan.Test/Unosquare.Swan.Test.csproj
@@ -7,9 +7,12 @@
net46;netcoreapp2.0
Unosquare.Swan.Test
..\..\StyleCop.Analyzers.ruleset
- Full
+
+ Full
+
+