diff options
Diffstat (limited to 'src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs')
-rw-r--r-- | src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs | 110 |
1 files changed, 86 insertions, 24 deletions
diff --git a/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs b/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs index 4fc89a7..c6151bb 100644 --- a/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs +++ b/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs @@ -4,22 +4,22 @@ // </copyright> //----------------------------------------------------------------------- -namespace DotNetOpenAuth.Test.Messaging -{ +namespace DotNetOpenAuth.Test.Messaging { using System; using System.Collections.Generic; using System.Collections.Specialized; + using System.Diagnostics; using System.IO; using System.Net; using System.Text.RegularExpressions; using System.Web; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.Test.Mocks; - using Microsoft.VisualStudio.TestTools.UnitTesting; + using NUnit.Framework; - [TestClass] + [TestFixture] public class MessagingUtilitiesTests : TestBase { - [TestMethod] + [TestCase] public void CreateQueryString() { var args = new Dictionary<string, string>(); args.Add("a", "b"); @@ -27,17 +27,17 @@ namespace DotNetOpenAuth.Test.Messaging Assert.AreEqual("a=b&c%2Fd=e%2Ff", MessagingUtilities.CreateQueryString(args)); } - [TestMethod] + [TestCase] public void CreateQueryStringEmptyCollection() { Assert.AreEqual(0, MessagingUtilities.CreateQueryString(new Dictionary<string, string>()).Length); } - [TestMethod, ExpectedException(typeof(ArgumentNullException))] + [TestCase, ExpectedException(typeof(ArgumentNullException))] public void CreateQueryStringNullDictionary() { MessagingUtilities.CreateQueryString(null); } - [TestMethod] + [TestCase] public void AppendQueryArgs() { UriBuilder uri = new UriBuilder("http://baseline.org/page"); var args = new Dictionary<string, string>(); @@ -51,17 +51,17 @@ namespace DotNetOpenAuth.Test.Messaging Assert.AreEqual("http://baseline.org/page?a=b&c%2Fd=e%2Ff&g=h", uri.Uri.AbsoluteUri); } - [TestMethod, ExpectedException(typeof(ArgumentNullException))] + [TestCase, ExpectedException(typeof(ArgumentNullException))] public void AppendQueryArgsNullUriBuilder() { MessagingUtilities.AppendQueryArgs(null, new Dictionary<string, string>()); } - [TestMethod] + [TestCase] public void AppendQueryArgsNullDictionary() { MessagingUtilities.AppendQueryArgs(new UriBuilder(), null); } - [TestMethod] + [TestCase] public void ToDictionary() { NameValueCollection nvc = new NameValueCollection(); nvc["a"] = "b"; @@ -73,7 +73,7 @@ namespace DotNetOpenAuth.Test.Messaging Assert.AreEqual(nvc["c"], actual["c"]); } - [TestMethod, ExpectedException(typeof(ArgumentException))] + [TestCase, ExpectedException(typeof(ArgumentException))] public void ToDictionaryWithNullKey() { NameValueCollection nvc = new NameValueCollection(); nvc[null] = "a"; @@ -81,7 +81,7 @@ namespace DotNetOpenAuth.Test.Messaging nvc.ToDictionary(true); } - [TestMethod] + [TestCase] public void ToDictionaryWithSkippedNullKey() { NameValueCollection nvc = new NameValueCollection(); nvc[null] = "a"; @@ -91,27 +91,27 @@ namespace DotNetOpenAuth.Test.Messaging Assert.AreEqual(nvc["b"], dictionary["b"]); } - [TestMethod] + [TestCase] public void ToDictionaryNull() { Assert.IsNull(MessagingUtilities.ToDictionary(null)); } - [TestMethod, ExpectedException(typeof(ArgumentNullException))] + [TestCase, ExpectedException(typeof(ArgumentNullException))] public void ApplyHeadersToResponseNullAspNetResponse() { MessagingUtilities.ApplyHeadersToResponse(new WebHeaderCollection(), (HttpResponse)null); } - [TestMethod, ExpectedException(typeof(ArgumentNullException))] + [TestCase, ExpectedException(typeof(ArgumentNullException))] public void ApplyHeadersToResponseNullListenerResponse() { MessagingUtilities.ApplyHeadersToResponse(new WebHeaderCollection(), (HttpListenerResponse)null); } - [TestMethod, ExpectedException(typeof(ArgumentNullException))] + [TestCase, ExpectedException(typeof(ArgumentNullException))] public void ApplyHeadersToResponseNullHeaders() { MessagingUtilities.ApplyHeadersToResponse(null, new HttpResponse(new StringWriter())); } - [TestMethod] + [TestCase] public void ApplyHeadersToResponse() { var headers = new WebHeaderCollection(); headers[HttpResponseHeader.ContentType] = "application/binary"; @@ -128,7 +128,7 @@ namespace DotNetOpenAuth.Test.Messaging /// <remarks> /// The tests in this method come from http://wiki.oauth.net/TestCases /// </remarks> - [TestMethod] + [TestCase] public void EscapeUriDataStringRfc3986Tests() { Assert.AreEqual("abcABC123", MessagingUtilities.EscapeUriDataStringRfc3986("abcABC123")); Assert.AreEqual("-._~", MessagingUtilities.EscapeUriDataStringRfc3986("-._~")); @@ -145,7 +145,7 @@ namespace DotNetOpenAuth.Test.Messaging /// <summary> /// Verifies the overall format of the multipart POST is correct. /// </summary> - [TestMethod] + [TestCase] public void PostMultipart() { var httpHandler = new TestWebRequestHandler(); bool callbackTriggered = false; @@ -174,7 +174,7 @@ namespace DotNetOpenAuth.Test.Messaging /// <summary> /// Verifies proper behavior of GetHttpVerb /// </summary> - [TestMethod] + [TestCase] public void GetHttpVerbTest() { Assert.AreEqual("GET", MessagingUtilities.GetHttpVerb(HttpDeliveryMethods.GetRequest)); Assert.AreEqual("POST", MessagingUtilities.GetHttpVerb(HttpDeliveryMethods.PostRequest)); @@ -192,7 +192,7 @@ namespace DotNetOpenAuth.Test.Messaging /// <summary> /// Verifies proper behavior of GetHttpVerb on invalid input. /// </summary> - [TestMethod, ExpectedException(typeof(ArgumentException))] + [TestCase, ExpectedException(typeof(ArgumentException))] public void GetHttpVerbOutOfRangeTest() { MessagingUtilities.GetHttpVerb(HttpDeliveryMethods.PutRequest | HttpDeliveryMethods.PostRequest); } @@ -200,7 +200,7 @@ namespace DotNetOpenAuth.Test.Messaging /// <summary> /// Verifies proper behavior of GetHttpDeliveryMethod /// </summary> - [TestMethod] + [TestCase] public void GetHttpDeliveryMethodTest() { Assert.AreEqual(HttpDeliveryMethods.GetRequest, MessagingUtilities.GetHttpDeliveryMethod("GET")); Assert.AreEqual(HttpDeliveryMethods.PostRequest, MessagingUtilities.GetHttpDeliveryMethod("POST")); @@ -212,9 +212,71 @@ namespace DotNetOpenAuth.Test.Messaging /// <summary> /// Verifies proper behavior of GetHttpDeliveryMethod for an unexpected input /// </summary> - [TestMethod, ExpectedException(typeof(ArgumentException))] + [TestCase, ExpectedException(typeof(ArgumentException))] public void GetHttpDeliveryMethodOutOfRangeTest() { MessagingUtilities.GetHttpDeliveryMethod("UNRECOGNIZED"); } + + /// <summary> + /// Verifies that the time-independent string equality check works accurately. + /// </summary> + [TestCase] + public void EqualsConstantTime() { + this.EqualsConstantTimeHelper(null, null); + this.EqualsConstantTimeHelper(null, string.Empty); + this.EqualsConstantTimeHelper(string.Empty, string.Empty); + this.EqualsConstantTimeHelper(string.Empty, "a"); + this.EqualsConstantTimeHelper(null, "a"); + this.EqualsConstantTimeHelper("a", "a"); + this.EqualsConstantTimeHelper("a", "A"); + this.EqualsConstantTimeHelper("A", "A"); + this.EqualsConstantTimeHelper("ab", "ab"); + this.EqualsConstantTimeHelper("ab", "b"); + } + + /// <summary> + /// Verifies that EqualsConstantTime actually has the same execution time regardless of how well a value matches. + /// </summary> + [TestCase] + public void EqualsConstantTimeIsActuallyConstantTime() { + string expected = new string('A', 5000); + string totalmismatch = new string('B', 5000); + string almostmatch = new string('A', 4999) + 'B'; + + const int Iterations = 4000; + var totalMismatchTimer = new Stopwatch(); + totalMismatchTimer.Start(); + for (int i = 0; i < Iterations; i++) { + MessagingUtilities.EqualsConstantTime(expected, totalmismatch); + } + totalMismatchTimer.Stop(); + + var almostMatchTimer = new Stopwatch(); + almostMatchTimer.Start(); + for (int i = 0; i < Iterations; i++) { + MessagingUtilities.EqualsConstantTime(expected, almostmatch); + } + almostMatchTimer.Stop(); + + const double ToleranceFactor = 0.06; + long averageTimeTicks = (totalMismatchTimer.ElapsedTicks + almostMatchTimer.ElapsedTicks) / 2; + var tolerableDifference = TimeSpan.FromTicks((long)(averageTimeTicks * ToleranceFactor)); + var absoluteDifference = TimeSpan.FromTicks(Math.Abs(totalMismatchTimer.ElapsedTicks - almostMatchTimer.ElapsedTicks)); + double actualFactor = (double)absoluteDifference.Ticks / averageTimeTicks; + Assert.IsTrue(absoluteDifference <= tolerableDifference, "A total mismatch took {0} but a near match took {1}, which is too different to be indistinguishable. The tolerable difference is {2} but the actual difference is {3}. This represents a difference of {4}%, beyond the tolerated {5}%.", totalMismatchTimer.Elapsed, almostMatchTimer.Elapsed, tolerableDifference, absoluteDifference, Math.Round(actualFactor * 100), Math.Round(ToleranceFactor * 100)); + Console.WriteLine("A total mismatch took {0} and a near match took {1}. The tolerable difference is {2}, and the actual difference is {3}. This represents a difference of {4}%, within the tolerated {5}%.", totalMismatchTimer.Elapsed, almostMatchTimer.Elapsed, tolerableDifference, absoluteDifference, Math.Round(actualFactor * 100), Math.Round(ToleranceFactor * 100)); + Console.WriteLine("The equality test execution time difference was only {0}%, within the tolerable {1}%", Math.Round(100 * actualFactor), Math.Round(ToleranceFactor * 100)); + } + + /// <summary> + /// Verifies that the time-independent string equality check works for a given pair of strings. + /// </summary> + /// <param name="value1">The first value.</param> + /// <param name="value2">The second value.</param> + private void EqualsConstantTimeHelper(string value1, string value2) { + bool expected = string.Equals(value1, value2, StringComparison.Ordinal); + Assert.AreEqual(expected, MessagingUtilities.EqualsConstantTime(value1, value2)); + Assert.AreEqual(expected, MessagingUtilities.EqualsConstantTime(value2, value1)); + } } } |