From 4dd5b9702a7d0db7dd85001fff54e82274527351 Mon Sep 17 00:00:00 2001 From: info Date: Mon, 30 Jan 2017 14:56:17 +0100 Subject: [PATCH] Add project files. --- WebLinksNet.Tests/Properties/AssemblyInfo.cs | 36 ++++++ WebLinksNet.Tests/WebLinksNet.Tests.csproj | 89 ++++++++++++++ WebLinksNet.Tests/WebLinksParserTests.cs | 76 ++++++++++++ WebLinksNet.sln | 58 ++++++++++ WebLinksNet/Properties/AssemblyInfo.cs | 36 ++++++ WebLinksNet/WebLink.cs | 90 +++++++++++++++ WebLinksNet/WebLinksCollection.cs | 22 ++++ WebLinksNet/WebLinksNet.csproj | 57 +++++++++ WebLinksNet/WebLinksParser.cs | 115 +++++++++++++++++++ WebLinksNet/WebLinksParserException.cs | 15 +++ 10 files changed, 594 insertions(+) create mode 100644 WebLinksNet.Tests/Properties/AssemblyInfo.cs create mode 100644 WebLinksNet.Tests/WebLinksNet.Tests.csproj create mode 100644 WebLinksNet.Tests/WebLinksParserTests.cs create mode 100644 WebLinksNet.sln create mode 100644 WebLinksNet/Properties/AssemblyInfo.cs create mode 100644 WebLinksNet/WebLink.cs create mode 100644 WebLinksNet/WebLinksCollection.cs create mode 100644 WebLinksNet/WebLinksNet.csproj create mode 100644 WebLinksNet/WebLinksParser.cs create mode 100644 WebLinksNet/WebLinksParserException.cs diff --git a/WebLinksNet.Tests/Properties/AssemblyInfo.cs b/WebLinksNet.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..83a8942 --- /dev/null +++ b/WebLinksNet.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("WebLinksNet.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WebLinksNet.Tests")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9d2104c5-1897-4f3d-90ec-0491ed303d1f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/WebLinksNet.Tests/WebLinksNet.Tests.csproj b/WebLinksNet.Tests/WebLinksNet.Tests.csproj new file mode 100644 index 0000000..996b11d --- /dev/null +++ b/WebLinksNet.Tests/WebLinksNet.Tests.csproj @@ -0,0 +1,89 @@ + + + + Debug + AnyCPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F} + Library + Properties + WebLinksNet.Tests + WebLinksNet.Tests + v4.6.1 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + {395e7bc1-1042-4094-8426-3935ce0fe36a} + WebLinksNet + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/WebLinksNet.Tests/WebLinksParserTests.cs b/WebLinksNet.Tests/WebLinksParserTests.cs new file mode 100644 index 0000000..41f2d85 --- /dev/null +++ b/WebLinksNet.Tests/WebLinksParserTests.cs @@ -0,0 +1,76 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using WebLinksNet; + +namespace WebLinksNet.Tests +{ + [TestClass] + public class WebLinksParserTests + { + /// + /// Test the execution of the parser with an empty parameter. An empty list should be returned. + /// + [TestMethod] + public void TestEmpty() + { + var result = WebLinksParser.Parse(""); + Assert.IsNotNull(result); + Assert.IsTrue(result.Count == 0); + } + + /// + /// Test the execution of the parser with a null parameter. An exception should be thrown. + /// + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void TestNull() + { + WebLinksParser.Parse(null); + } + + /// + /// Parse a simple WebLink + /// + [TestMethod] + public void TestSimpleParse() + { + var result = WebLinksParser.Parse("; rel=\"next\" title=\"This is a test\""); + + Assert.IsNotNull(result); + Assert.IsTrue(result.Count == 1); + + var webLink = result[0]; + Assert.AreEqual("/entries?page=2", webLink.Url, "Url property"); + Assert.AreEqual("next", webLink.Rel, "Rel property"); + Assert.AreEqual("This is a test", webLink.Title, "Title proprty"); + } + + /// + /// Parse Test parsing multiple WebLinks + /// + [TestMethod] + public void TestMultipleParse() + { + var result = WebLinksParser.Parse("; rel=\"next\", ; rel=\"last\""); + + Assert.IsNotNull(result); + Assert.IsTrue(result.Count == 2); + } + + /// + /// Tests if a WebLink .ToString() works as expected + /// + [TestMethod] + public void TestWebLinkToString() + { + var webLink = new WebLink() + { + Url = "/entries?page=2", + Title = "Simple Title", + Rel = "next" + }; + + Assert.AreEqual("", webLink.ToString()); + } + } +} diff --git a/WebLinksNet.sln b/WebLinksNet.sln new file mode 100644 index 0000000..dbd5e59 --- /dev/null +++ b/WebLinksNet.sln @@ -0,0 +1,58 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebLinksNet", "WebLinksNet\WebLinksNet.csproj", "{395E7BC1-1042-4094-8426-3935CE0FE36A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebLinksNet.Tests", "WebLinksNet.Tests\WebLinksNet.Tests.csproj", "{9D2104C5-1897-4F3D-90EC-0491ED303D1F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Debug|ARM.Build.0 = Debug|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Debug|x64.ActiveCfg = Debug|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Debug|x64.Build.0 = Debug|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Debug|x86.ActiveCfg = Debug|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Debug|x86.Build.0 = Debug|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Release|Any CPU.Build.0 = Release|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Release|ARM.ActiveCfg = Release|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Release|ARM.Build.0 = Release|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Release|x64.ActiveCfg = Release|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Release|x64.Build.0 = Release|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Release|x86.ActiveCfg = Release|Any CPU + {395E7BC1-1042-4094-8426-3935CE0FE36A}.Release|x86.Build.0 = Release|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Debug|ARM.ActiveCfg = Debug|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Debug|ARM.Build.0 = Debug|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Debug|x64.ActiveCfg = Debug|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Debug|x64.Build.0 = Debug|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Debug|x86.ActiveCfg = Debug|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Debug|x86.Build.0 = Debug|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Release|Any CPU.Build.0 = Release|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Release|ARM.ActiveCfg = Release|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Release|ARM.Build.0 = Release|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Release|x64.ActiveCfg = Release|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Release|x64.Build.0 = Release|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Release|x86.ActiveCfg = Release|Any CPU + {9D2104C5-1897-4F3D-90EC-0491ED303D1F}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/WebLinksNet/Properties/AssemblyInfo.cs b/WebLinksNet/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c5de575 --- /dev/null +++ b/WebLinksNet/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("WebLinksNet")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WebLinksNet")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("395e7bc1-1042-4094-8426-3935ce0fe36a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/WebLinksNet/WebLink.cs b/WebLinksNet/WebLink.cs new file mode 100644 index 0000000..89f0cb8 --- /dev/null +++ b/WebLinksNet/WebLink.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WebLinksNet +{ + /// + /// A WebLink object representing the web link data + /// + public class WebLink + { + /// + /// The list of attributes of the WebLink + /// + private readonly Dictionary _attributes = new Dictionary(); + + /// + /// The URL of the link + /// + public string Url { get; set; } = null; + + /// + /// The title of the link + /// + public string Title + { + get + { + return this._attributes.ContainsKey("title") ? this._attributes["title"] : null; + } + set + { + this._attributes["title"] = value; + } + } + + /// + /// The rel attribute of the link + /// + public string Rel + { + get + { + return this._attributes.ContainsKey("rel") ? this._attributes["rel"] : null; + } + set + { + this._attributes["rel"] = value; + } + } + + /// + /// Returns a textual representation of the WebLink + /// + /// + public override string ToString() + { + var sb = new StringBuilder(); + + sb.Append('<'); + sb.Append(this.Url); + sb.Append(">; "); + + foreach (var attr in this._attributes) + { + sb.Append('<'); + } + + return ""; + } + + /// + /// Register an attribute to the WebLink object + /// + /// + /// + internal void AddAttribute(string attributeName, string attributeValue) + { + // Validate parameters + if (string.IsNullOrWhiteSpace(attributeName)) + { + throw new ArgumentNullException(nameof(attributeName)); + } + + this._attributes.Add(attributeName, attributeValue); + } + } +} diff --git a/WebLinksNet/WebLinksCollection.cs b/WebLinksNet/WebLinksCollection.cs new file mode 100644 index 0000000..23ee3a4 --- /dev/null +++ b/WebLinksNet/WebLinksCollection.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WebLinks +{ + /// + /// A collection of web links + /// + public class WebLinksCollection + { + /// + /// Create a new weblinks collection + /// + public WebLinksCollection() + { + + } + } +} diff --git a/WebLinksNet/WebLinksNet.csproj b/WebLinksNet/WebLinksNet.csproj new file mode 100644 index 0000000..e5979b3 --- /dev/null +++ b/WebLinksNet/WebLinksNet.csproj @@ -0,0 +1,57 @@ + + + + + Debug + AnyCPU + {395E7BC1-1042-4094-8426-3935CE0FE36A} + Library + Properties + WebLinksNet + WebLinksNet + v4.6.1 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WebLinksNet/WebLinksParser.cs b/WebLinksNet/WebLinksParser.cs new file mode 100644 index 0000000..0b31f2b --- /dev/null +++ b/WebLinksNet/WebLinksParser.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WebLinksNet +{ + /// + /// An internal class used for parsing the WebLinks + /// + public class WebLinksParser + { + /// + /// Parses the given weblink header and returns a list of WebLink objects + /// + /// + /// + public static List Parse(string webLinkHeader) + { + // Validate the parameters + if (webLinkHeader == null) + { + throw new ArgumentNullException(nameof(webLinkHeader)); + } + + var attributeNameBuilder = new StringBuilder(); + + // Parse the data + var list = new List(); + + var webLinkParts = webLinkHeader.Split(','); + for(var i = 0; i < webLinkParts.Length; i++) + { + var webLink = new WebLink(); + + var part = webLinkParts[i].Trim(); + // Simple validation + if ((!part.StartsWith("<") || !part.Contains(">"))) + { + if(string.IsNullOrWhiteSpace(part)) + { + continue; + } + else + { + throw new WebLinksParserException(); + } + } + + // Parse the URL + var urlEndIndex = part.IndexOf('>') - 1; + webLink.Url = part.Substring(1, urlEndIndex); + + attributeNameBuilder.Clear(); + for (var n = urlEndIndex + 3; n < part.Length; n++) + { + var c = part[n]; + + // These characters should not be present here + if (c == '"' || c == '<' || c == '>' || c == ',') + throw new WebLinksParserException(); + + if (c != '=') + { + attributeNameBuilder.Append(c); + continue; + } + + // Clean up and validate the name + var name = attributeNameBuilder.ToString(); + attributeNameBuilder.Clear(); + name = name.Trim(); + foreach (var nameChar in name) + { + if (char.IsWhiteSpace(nameChar)) + { + throw new WebLinksParserException(); + } + } + + // Read the value + string value = ""; + while (n < part.Length) + { + n++; + + if (char.IsWhiteSpace(part[n])) + { + continue; + } + else if (part[n] == '"') + { + // Read the value + var valueEndIndex = part.IndexOf('"', n + 1); + value = part.Substring(n + 1, valueEndIndex - n - 1); + + + // Advance the original loop + n = valueEndIndex; + break; + } + } + + // Construct an attribute + webLink.AddAttribute(name, value); + } + + list.Add(webLink); + } + + return list; + } + } +} diff --git a/WebLinksNet/WebLinksParserException.cs b/WebLinksNet/WebLinksParserException.cs new file mode 100644 index 0000000..323b534 --- /dev/null +++ b/WebLinksNet/WebLinksParserException.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WebLinksNet +{ + /// + /// The exception thrown when an error occured during parsing of WebLinks objects + /// + public class WebLinksParserException : Exception + { + } +}