Skip to content

Commit

Permalink
Issue 49 CS project parser (#50)
Browse files Browse the repository at this point in the history
* Base classes

* Add CsProjFile tests

* Add constructor to CsProjFile

* Versioning

* Fix Test

* Add CsProjFile constructor tests

* Checking issue

* Change LDAP test

* Add Universal Time to Test

* Remove buggy test case
  • Loading branch information
geoperez authored Dec 1, 2017
1 parent 387e3f5 commit e57d7b8
Show file tree
Hide file tree
Showing 8 changed files with 321 additions and 6 deletions.
100 changes: 100 additions & 0 deletions src/Unosquare.Swan/Components/CsProjFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
namespace Unosquare.Swan.Components
{
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;

/// <summary>
/// Represents a CsProjFile parser
/// Based on https://github.com/maartenba/dotnetcli-init
/// </summary>
/// <typeparam name="T">The type of <c>CsProjMetadataBase</c></typeparam>
/// <seealso cref="System.IDisposable" />
public class CsProjFile<T>
: IDisposable
where T : CsProjMetadataBase
{
private readonly Stream _stream;
private readonly bool _leaveOpen;
private readonly XDocument _xmlDocument;

/// <summary>
/// Initializes a new instance of the <see cref="CsProjFile{T}"/> class.
/// </summary>
/// <param name="filename">The filename.</param>
public CsProjFile(string filename = null)
: this(OpenFile(filename))
{
// placeholder
}

/// <summary>
/// Initializes a new instance of the <see cref="CsProjFile{T}"/> class.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="leaveOpen">if set to <c>true</c> [leave open].</param>
/// <exception cref="ArgumentException">Project file is not of the new .csproj type.</exception>
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<T>();
Metadata.SetData(_xmlDocument);
}

/// <summary>
/// Gets the metadata.
/// </summary>
/// <value>
/// The nu get metadata.
/// </value>
public T Metadata { get; }

/// <summary>
/// Saves this instance.
/// </summary>
public void Save()
{
_stream.SetLength(0);
_stream.Position = 0;

_xmlDocument.Save(_stream);
}

/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
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);
}
}
}
79 changes: 79 additions & 0 deletions src/Unosquare.Swan/Components/CsProjMetadataBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
namespace Unosquare.Swan.Components
{
using System.Linq;
using System.Xml.Linq;

/// <summary>
/// Represents a CsProj metadata abstract class
/// to use with <c>CsProjFile</c> parser.
/// </summary>
public abstract class CsProjMetadataBase
{
private XDocument _xmlDocument;

/// <summary>
/// Gets the package identifier.
/// </summary>
/// <value>
/// The package identifier.
/// </value>
public string PackageId => FindElement(nameof(PackageId))?.Value;

/// <summary>
/// Gets the name of the assembly.
/// </summary>
/// <value>
/// The name of the assembly.
/// </value>
public string AssemblyName => FindElement(nameof(AssemblyName))?.Value;

/// <summary>
/// Gets the target frameworks.
/// </summary>
/// <value>
/// The target frameworks.
/// </value>
public string TargetFrameworks => FindElement(nameof(TargetFrameworks))?.Value;

/// <summary>
/// Gets the target framework.
/// </summary>
/// <value>
/// The target framework.
/// </value>
public string TargetFramework => FindElement(nameof(TargetFramework))?.Value;

/// <summary>
/// Gets the version.
/// </summary>
/// <value>
/// The version.
/// </value>
public string Version => FindElement(nameof(Version))?.Value;

/// <summary>
/// Parses the cs proj tags.
/// </summary>
/// <param name="args">The arguments.</param>
public abstract void ParseCsProjTags(ref string[] args);

/// <summary>
/// Sets the data.
/// </summary>
/// <param name="xmlDocument">The XML document.</param>
public void SetData(XDocument xmlDocument)
{
_xmlDocument = xmlDocument;
}

/// <summary>
/// Finds the element.
/// </summary>
/// <param name="elementName">Name of the element.</param>
/// <returns>A XElement.</returns>
protected XElement FindElement(string elementName)
{
return _xmlDocument.Descendants(elementName).FirstOrDefault();
}
}
}
2 changes: 1 addition & 1 deletion src/Unosquare.Swan/Unosquare.Swan.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PackageId>Unosquare.Swan</PackageId>
<CodeAnalysisRuleSet>..\..\StyleCop.Analyzers.ruleset</CodeAnalysisRuleSet>
<DebugType>Full</DebugType>
<Version>0.21.1</Version>
<Version>0.22.0</Version>
<Authors>Unosquare</Authors>
<PackageIconUrl>https://github.com/unosquare/swan/raw/master/swan-logo-32.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/unosquare/swan</PackageProjectUrl>
Expand Down
101 changes: 101 additions & 0 deletions test/Unosquare.Swan.Test/CsProjFileTest.cs
Original file line number Diff line number Diff line change
@@ -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 = @"<Project Sdk=""Microsoft.NET.Sdk"">
<PropertyGroup>
<Description>Unit Testing project</Description>
<Copyright>Copyright(c) 2016-2017 - Unosquare</Copyright>
<AssemblyTitle>Unosquare SWAN Test</AssemblyTitle>
<TargetFrameworks>net46;netcoreapp2.0</TargetFrameworks>
<AssemblyName>Unosquare.Swan.Test</AssemblyName>
<DebugType>Full</DebugType>
</PropertyGroup></Project>";
protected string _wrongSDK = @"<Project Sdk=""Microhard.NET.Sdk""></Project>";
}

[TestFixture]
public class CsProjFileConstructor : CsProjFileTest
{
[Test]
public void WithValidFileAndValidClass_ReturnsFileAndMetadata()
{
using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
using (var csproj = new CsProjFile<CsMetadataMock>(stream))
{
Assert.IsNotNull(csproj);
Assert.IsNotNull(csproj.Metadata);
Assert.IsNotNull(csproj.Metadata.Copyright);
}
}

[Test]
public void WithNullStream_ThrowsXmlException()
{
Assert.Throws<XmlException>(() =>
{
using (var stream = new MemoryStream())
using (var csproj = new CsProjFile<CsMetadataMock>(stream)) { }
});
}

[Test]
public void IfPropertyWasNotFound_ReturnsNull()
{
using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
using (var csproj = new CsProjFile<CsMetadataMock>(stream))
{
Assert.IsNull(csproj.Metadata.NonExistentProp);
}
}

[Test]
public void WithWrongSdk_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() =>
{
using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_wrongSDK)))
using (var csproj = new CsProjFile<CsMetadataMock>(stream)){}
});
}

[Test]
public void WithAbstractClass_ThrowsMissingMethodException()
{
Assert.Throws<MissingMethodException>(() =>
{
using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
using (var csproj = new CsProjFile<CsAbstractMetadataMock>(stream)) { }
});
}

[Test]
public void WithEmptyStringAsFileName_ThrowsArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() =>
{
using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
using (var csproj = new CsProjFile<CsAbstractMetadataMock>(string.Empty)) { }
});
}

[Test]
public void WithNullAsFileName_ThrowsArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() =>
{
using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(_data)))
using (var csproj = new CsProjFile<CsAbstractMetadataMock>(null)) { }
});
}
}
}
2 changes: 1 addition & 1 deletion test/Unosquare.Swan.Test/ExtensionsDatesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
9 changes: 6 additions & 3 deletions test/Unosquare.Swan.Test/LdapTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,17 +183,20 @@ public class ModifyTest : LdapTest
[Test]
public void ChangeUserProperty()
{
var ex = Assert.ThrowsAsync<LdapException>(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", "[email protected]")});
new[] {new LdapModification(LdapModificationOp.Replace, "mail", "[email protected]")});
cn.Disconnect();
});

Assert.AreEqual(ex.ResultCode, LdapStatusCode.InsufficientAccessRights);
if (ex is LdapException ldapEx)
Assert.AreEqual(ldapEx.ResultCode, LdapStatusCode.InsufficientAccessRights);
else
Assert.IsNotNull(ex);
}
}

Expand Down
29 changes: 29 additions & 0 deletions test/Unosquare.Swan.Test/Mocks/CsProjFileMock.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
5 changes: 4 additions & 1 deletion test/Unosquare.Swan.Test/Unosquare.Swan.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
<TargetFrameworks>net46;netcoreapp2.0</TargetFrameworks>
<AssemblyName>Unosquare.Swan.Test</AssemblyName>
<CodeAnalysisRuleSet>..\..\StyleCop.Analyzers.ruleset</CodeAnalysisRuleSet>
<DebugType>Full</DebugType>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net46' ">
<DebugType>Full</DebugType>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Unosquare.Swan\Unosquare.Swan.csproj" />
</ItemGroup>
Expand Down

0 comments on commit e57d7b8

Please sign in to comment.