summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2008-11-08 19:11:56 -0800
committerAndrew <andrewarnott@gmail.com>2008-11-08 19:11:56 -0800
commit9ebbf7e45657fca07ec70374bab820f21c964e47 (patch)
treead5a342117750d7ec537b68cda1d0e4e78613c10 /src
parente16b0c1bfd1825485cb2c8461655e884f0ecac5a (diff)
downloadDotNetOpenAuth-9ebbf7e45657fca07ec70374bab820f21c964e47.zip
DotNetOpenAuth-9ebbf7e45657fca07ec70374bab820f21c964e47.tar.gz
DotNetOpenAuth-9ebbf7e45657fca07ec70374bab820f21c964e47.tar.bz2
Added tests for OpenIdChannel and KeyValueForm encoder.
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj4
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/TestWebRequestHandler.cs30
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/ChannelElements/KeyValueFormEncodingTests.cs162
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/ChannelElements/OpenIdChannelTests.cs89
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/OpenIdChannelTests.cs28
-rw-r--r--src/DotNetOpenAuth.Test/TestUtilities.cs45
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs8
7 files changed, 336 insertions, 30 deletions
diff --git a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj
index ca1e93c..18cd704 100644
--- a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj
+++ b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj
@@ -92,17 +92,19 @@
<Compile Include="OAuth\ConsumerDescription.cs" />
<Compile Include="OAuth\ProtocolTests.cs" />
<Compile Include="OAuth\ServiceProviderDescriptionTests.cs" />
+ <Compile Include="OpenId\ChannelElements\KeyValueFormEncodingTests.cs" />
<Compile Include="OpenId\Messages\AssociateDiffieHellmanRequestTests.cs" />
<Compile Include="OpenId\Messages\AssociateRequestTests.cs" />
<Compile Include="OpenId\Messages\AssociateUnsuccessfulResponseTests.cs" />
<Compile Include="OpenId\Messages\AssociateUnencryptedResponseTests.cs" />
- <Compile Include="OpenId\OpenIdChannelTests.cs" />
+ <Compile Include="OpenId\ChannelElements\OpenIdChannelTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Messaging\ResponseTests.cs" />
<Compile Include="Scenarios\AppendixScenarios.cs" />
<Compile Include="Scenarios\CoordinatingOAuthChannel.cs" />
<Compile Include="Scenarios\Coordinator.cs" />
<Compile Include="TestBase.cs" />
+ <Compile Include="TestUtilities.cs" />
<Compile Include="UriUtilTests.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/src/DotNetOpenAuth.Test/Mocks/TestWebRequestHandler.cs b/src/DotNetOpenAuth.Test/Mocks/TestWebRequestHandler.cs
index d7092b4..7117bc1 100644
--- a/src/DotNetOpenAuth.Test/Mocks/TestWebRequestHandler.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/TestWebRequestHandler.cs
@@ -15,8 +15,14 @@ namespace DotNetOpenAuth.Test.Mocks {
internal class TestWebRequestHandler : IWebRequestHandler {
private StringBuilder postEntity;
+ /// <summary>
+ /// Gets or sets the callback used to provide the mock response for the mock request.
+ /// </summary>
internal Func<HttpWebRequest, Response> Callback { get; set; }
+ /// <summary>
+ /// Gets the stream that was written out as if on an HTTP request.
+ /// </summary>
internal Stream RequestEntityStream {
get {
if (this.postEntity == null) {
@@ -26,13 +32,37 @@ namespace DotNetOpenAuth.Test.Mocks {
}
}
+ /// <summary>
+ /// Gets the stream that was written out as if on an HTTP request as an ordinary string.
+ /// </summary>
+ internal string RequestEntityAsString {
+ get {
+ return this.postEntity != null ? this.postEntity.ToString() : null;
+ }
+ }
+
#region IWebRequestHandler Members
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <returns>
+ /// The writer the caller should write out the entity data to.
+ /// </returns>
public TextWriter GetRequestStream(HttpWebRequest request) {
this.postEntity = new StringBuilder();
return new StringWriter(this.postEntity);
}
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="Response"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <returns>
+ /// An instance of <see cref="Response"/> describing the response.
+ /// </returns>
public Response GetResponse(HttpWebRequest request) {
if (this.Callback == null) {
throw new InvalidOperationException("Set the Callback property first.");
diff --git a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/KeyValueFormEncodingTests.cs b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/KeyValueFormEncodingTests.cs
new file mode 100644
index 0000000..e625499
--- /dev/null
+++ b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/KeyValueFormEncodingTests.cs
@@ -0,0 +1,162 @@
+//-----------------------------------------------------------------------
+// <copyright file="KeyValueFormEncodingTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.OpenId.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Net;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Reflection;
+ using DotNetOpenAuth.OpenId.ChannelElements;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class KeyValueFormEncodingTests : TestBase {
+ private Dictionary<string, string> sampleData = new Dictionary<string, string> {
+ { "key1", "value1" },
+ { "key2", "value2:a" },
+ { "Key3", "Value3" },
+ };
+
+ private KeyValueFormEncoding keyValueForm = new KeyValueFormEncoding();
+
+ [Flags]
+ public enum TestMode {
+ Encoder = 0x1,
+ Decoder = 0x2,
+ Both = 0x3,
+ }
+
+ [TestMethod]
+ public void BasicEncodingTest() {
+ var kvf = new KeyValueFormEncoding();
+
+ byte[] kvfBytes = kvf.GetBytes(this.sampleData);
+ string responseString = Encoding.UTF8.GetString(kvfBytes);
+
+ Assert.IsFalse(responseString.Contains("\n\n"));
+ Assert.IsTrue(responseString.EndsWith("\n", StringComparison.Ordinal));
+ int count = 0;
+ foreach (string line in responseString.Split('\n')) {
+ if (line.Length == 0) {
+ break;
+ }
+ int colon = line.IndexOf(':');
+ Assert.IsTrue(colon > 0);
+ string key = line.Substring(0, colon);
+ string value = line.Substring(colon + 1);
+ Assert.AreEqual(this.sampleData[key], value);
+ count++;
+ }
+
+ Assert.AreEqual(this.sampleData.Count, count);
+ }
+
+ public void KVDictTest(byte[] kvform, IDictionary<string, string> dict, TestMode mode) {
+ if ((mode & TestMode.Decoder) == TestMode.Decoder) {
+ var d = this.keyValueForm.GetDictionary(new MemoryStream(kvform));
+ foreach (string key in dict.Keys) {
+ Assert.AreEqual(d[key], dict[key], "Decoder fault: " + d[key] + " and " + dict[key] + " do not match.");
+ }
+ }
+ if ((mode & TestMode.Encoder) == TestMode.Encoder) {
+ var e = this.keyValueForm.GetBytes(dict);
+ Assert.IsTrue(TestUtilities.AreEquivalent(e, kvform), "Encoder did not produced expected result.");
+ }
+ }
+
+ [TestMethod]
+ public void EncodeDecode() {
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes(string.Empty), new Dictionary<string, string>(), TestMode.Both);
+
+ Dictionary<string, string> d1 = new Dictionary<string, string>();
+ d1.Add("college", "harvey mudd");
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes("college:harvey mudd\n"), d1, TestMode.Both);
+
+ Dictionary<string, string> d2 = new Dictionary<string, string>();
+ d2.Add("city", "claremont");
+ d2.Add("state", "CA");
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes("city:claremont\nstate:CA\n"), d2, TestMode.Both);
+
+ Dictionary<string, string> d3 = new Dictionary<string, string>();
+ d3.Add("is_valid", "true");
+ d3.Add("invalidate_handle", "{HMAC-SHA1:2398410938412093}");
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes("is_valid:true\ninvalidate_handle:{HMAC-SHA1:2398410938412093}\n"), d3, TestMode.Both);
+
+ Dictionary<string, string> d4 = new Dictionary<string, string>();
+ d4.Add(string.Empty, string.Empty);
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes(":\n"), d4, TestMode.Both);
+
+ Dictionary<string, string> d5 = new Dictionary<string, string>();
+ d5.Add(string.Empty, "missingkey");
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes(":missingkey\n"), d5, TestMode.Both);
+
+ Dictionary<string, string> d6 = new Dictionary<string, string>();
+ d6.Add("street", "foothill blvd");
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes("street:foothill blvd\n"), d6, TestMode.Both);
+
+ Dictionary<string, string> d7 = new Dictionary<string, string>();
+ d7.Add("major", "computer science");
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes("major:computer science\n"), d7, TestMode.Both);
+
+ Dictionary<string, string> d8 = new Dictionary<string, string>();
+ d8.Add("dorm", "east");
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes(" dorm : east \n"), d8, TestMode.Decoder);
+
+ Dictionary<string, string> d9 = new Dictionary<string, string>();
+ d9.Add("e^(i*pi)+1", "0");
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes("e^(i*pi)+1:0"), d9, TestMode.Decoder);
+
+ Dictionary<string, string> d10 = new Dictionary<string, string>();
+ d10.Add("east", "west");
+ d10.Add("north", "south");
+ this.KVDictTest(UTF8Encoding.UTF8.GetBytes("east:west\nnorth:south"), d10, TestMode.Decoder);
+ }
+
+ [TestMethod, ExpectedException(typeof(ArgumentException))]
+ public void NoValue() {
+ this.Illegal("x\n", KeyValueFormConformanceLevel.OpenId11);
+ }
+
+ [TestMethod, ExpectedException(typeof(ArgumentException))]
+ public void NoValueLoose() {
+ Dictionary<string, string> d = new Dictionary<string, string>();
+ this.KVDictTest(Encoding.UTF8.GetBytes("x\n"), d, TestMode.Decoder);
+ }
+
+ [TestMethod, ExpectedException(typeof(ArgumentException))]
+ public void EmptyLine() {
+ this.Illegal("x:b\n\n", KeyValueFormConformanceLevel.OpenId20);
+ }
+
+ [TestMethod]
+ public void EmptyLineLoose() {
+ Dictionary<string, string> d = new Dictionary<string, string>();
+ d.Add("x", "b");
+ this.KVDictTest(Encoding.UTF8.GetBytes("x:b\n\n"), d, TestMode.Decoder);
+ }
+
+ [TestMethod, ExpectedException(typeof(ArgumentException))]
+ public void LastLineNotTerminated() {
+ this.Illegal("x:y\na:b", KeyValueFormConformanceLevel.OpenId11);
+ }
+
+ [TestMethod]
+ public void LastLineNotTerminatedLoose() {
+ Dictionary<string, string> d = new Dictionary<string, string>();
+ d.Add("x", "y");
+ d.Add("a", "b");
+ this.KVDictTest(Encoding.UTF8.GetBytes("x:y\na:b"), d, TestMode.Decoder);
+ }
+
+ private void Illegal(string s, KeyValueFormConformanceLevel level) {
+ new KeyValueFormEncoding(level).GetDictionary(new MemoryStream(Encoding.UTF8.GetBytes(s)));
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/OpenIdChannelTests.cs b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/OpenIdChannelTests.cs
new file mode 100644
index 0000000..898e1ce
--- /dev/null
+++ b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/OpenIdChannelTests.cs
@@ -0,0 +1,89 @@
+//-----------------------------------------------------------------------
+// <copyright file="OpenIdChannelTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.OpenId.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Net;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Reflection;
+ using DotNetOpenAuth.OpenId.ChannelElements;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class OpenIdChannelTests : TestBase {
+ private OpenIdChannel channel;
+ private OpenIdChannel_Accessor accessor;
+ private Mocks.TestWebRequestHandler webHandler;
+
+ [TestInitialize]
+ public void Setup() {
+ this.webHandler = new Mocks.TestWebRequestHandler();
+ this.channel = new OpenIdChannel();
+ this.accessor = OpenIdChannel_Accessor.AttachShadow(this.channel);
+ this.channel.WebRequestHandler = this.webHandler;
+ }
+
+ [TestMethod]
+ public void Ctor() {
+ }
+
+ /// <summary>
+ /// Verifies that the channel sends direct message requests as HTTP POST requests.
+ /// </summary>
+ [TestMethod]
+ public void DirectRequestsUsePost() {
+ IDirectedProtocolMessage requestMessage = new Mocks.TestDirectedMessage(MessageTransport.Direct) {
+ Recipient = new Uri("http://host"),
+ Name = "Andrew",
+ };
+ HttpWebRequest httpRequest = this.accessor.CreateHttpRequest(requestMessage);
+ Assert.AreEqual("POST", httpRequest.Method);
+ StringAssert.Contains(this.webHandler.RequestEntityAsString, "Name=Andrew");
+ }
+
+ /// <summary>
+ /// Verifies that direct response messages are encoded using Key Value Form.
+ /// </summary>
+ /// <remarks>
+ /// The validity of the actual KVF encoding is not checked here. We assume that the KVF encoding
+ /// class is verified elsewhere. We're only checking that the KVF class is being used by the
+ /// <see cref="OpenIdChannel.SendDirectMessageResponse"/> method.
+ /// </remarks>
+ [TestMethod]
+ public void DirectResponsesSentUsingKeyValueForm() {
+ IProtocolMessage message = MessagingTestBase.GetStandardTestMessage(MessagingTestBase.FieldFill.AllRequired);
+ MessageDictionary messageFields = new MessageDictionary(message);
+ byte[] expectedBytes = new KeyValueFormEncoding().GetBytes(messageFields);
+ string expectedContentType = OpenIdChannel_Accessor.KeyValueFormContentType;
+
+ Response directResponse = this.accessor.SendDirectMessageResponse(message);
+ Assert.AreEqual(expectedContentType, directResponse.Headers[HttpResponseHeader.ContentType]);
+ byte[] actualBytes = new byte[directResponse.ResponseStream.Length];
+ directResponse.ResponseStream.Read(actualBytes, 0, actualBytes.Length);
+ Assert.IsTrue(TestUtilities.AreEquivalent(expectedBytes, actualBytes));
+ }
+
+ /// <summary>
+ /// Verifies that direct message responses are read in using the Key Value Form decoder.
+ /// </summary>
+ [TestMethod]
+ public void DirectResponsesReceivedAsKeyValueForm() {
+ var fields = new Dictionary<string, string> {
+ { "var1", "value1" },
+ { "var2", "value2" },
+ };
+ KeyValueFormEncoding kvf = new KeyValueFormEncoding();
+ Response response = new Response {
+ ResponseStream = new MemoryStream(kvf.GetBytes(fields)),
+ };
+ Assert.IsTrue(TestUtilities.AreEquivalent(fields, this.accessor.ReadFromResponseInternal(response)));
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Test/OpenId/OpenIdChannelTests.cs b/src/DotNetOpenAuth.Test/OpenId/OpenIdChannelTests.cs
deleted file mode 100644
index 0843601..0000000
--- a/src/DotNetOpenAuth.Test/OpenId/OpenIdChannelTests.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OpenIdChannelTests.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.Test.OpenId {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using DotNetOpenAuth.OpenId.ChannelElements;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
-
- [TestClass]
- public class OpenIdChannelTests : TestBase {
- private OpenIdChannel channel;
-
- [TestInitialize]
- public void Setup() {
- this.channel = new OpenIdChannel();
- }
-
- [TestMethod]
- public void Ctor() {
- }
- }
-}
diff --git a/src/DotNetOpenAuth.Test/TestUtilities.cs b/src/DotNetOpenAuth.Test/TestUtilities.cs
new file mode 100644
index 0000000..3b70cc2
--- /dev/null
+++ b/src/DotNetOpenAuth.Test/TestUtilities.cs
@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------
+// <copyright file="TestUtilities.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ /// <summary>
+ /// An assortment of methods useful for testing.
+ /// </summary>
+ internal class TestUtilities {
+ /// <summary>
+ /// Tests whether two arrays are equal in length and contents.
+ /// </summary>
+ /// <typeparam name="T">The type of elements in the arrays.</typeparam>
+ /// <param name="first">The first array to test. May not be null.</param>
+ /// <param name="second">The second array to test. May not be null.</param>
+ /// <returns>True if the arrays equal; false otherwise.</returns>
+ public static bool AreEquivalent<T>(T[] first, T[] second) {
+ if (first == null) {
+ throw new ArgumentNullException("first");
+ }
+ if (second == null) {
+ throw new ArgumentNullException("second");
+ }
+ if (first.Length != second.Length) {
+ return false;
+ }
+ for (int i = 0; i < first.Length; i++) {
+ if (!first[i].Equals(second[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool AreEquivalent<TKey, TValue>(IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second) {
+ return AreEquivalent(first.ToArray(), second.ToArray());
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
index e13e09c..c514baf 100644
--- a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
@@ -20,6 +20,12 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// <summary>
/// The HTTP Content-Type to use in Key-Value Form responses.
/// </summary>
+ /// <remarks>
+ /// OpenID 2.0 section 5.1.2 says this SHOULD be text/plain. But this value
+ /// does not prevent free hosters like GoDaddy from tacking on their ads
+ /// to the end of the direct response, corrupting the data. So we deviate
+ /// from the spec a bit here to improve the story for free Providers.
+ /// </remarks>
private const string KeyValueFormContentType = "application/x-openid-kvf";
/// <summary>
@@ -89,7 +95,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
byte[] keyValueEncoding = this.keyValueForm.GetBytes(fields);
Response preparedResponse = new Response();
- preparedResponse.Headers.Add(HttpResponseHeader.ContentType, "application/x-openid-kvf");
+ preparedResponse.Headers.Add(HttpResponseHeader.ContentType, KeyValueFormContentType);
preparedResponse.OriginalMessage = response;
preparedResponse.ResponseStream = new MemoryStream(keyValueEncoding);