254 lines
12 KiB
C#
254 lines
12 KiB
C#
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Collections.Specialized;
|
|||
|
using System.Web;
|
|||
|
using System.Web.Helpers.Test;
|
|||
|
using System.Web.TestUtil;
|
|||
|
using System.Web.WebPages.Scope;
|
|||
|
using Moq;
|
|||
|
using Xunit;
|
|||
|
using Assert = Microsoft.TestCommon.AssertEx;
|
|||
|
|
|||
|
namespace Microsoft.Web.Helpers.Test
|
|||
|
{
|
|||
|
public class ReCaptchaTest
|
|||
|
{
|
|||
|
[Fact]
|
|||
|
public void ReCaptchaOptionsMissingWhenNoOptionsAndDefaultRendering()
|
|||
|
{
|
|||
|
var html = ReCaptcha.GetHtml(GetContext(), "PUBLIC_KEY");
|
|||
|
UnitTestHelper.AssertEqualsIgnoreWhitespace(
|
|||
|
@"<script src=""http://www.google.com/recaptcha/api/challenge?k=PUBLIC_KEY"" type=""text/javascript""></script>" +
|
|||
|
@"<noscript>" +
|
|||
|
@"<iframe frameborder=""0"" height=""300px"" src=""http://www.google.com/recaptcha/api/noscript?k=PUBLIC_KEY"" width=""500px""></iframe><br/><br/>" +
|
|||
|
@"<textarea cols=""40"" name=""recaptcha_challenge_field"" rows=""3""></textarea>" +
|
|||
|
@"<input name=""recaptcha_response_field"" type=""hidden"" value=""manual_challenge""/>" +
|
|||
|
@"</noscript>",
|
|||
|
html.ToString());
|
|||
|
XhtmlAssert.Validate1_0(html, addRoot: true);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ReCaptchaOptionsWhenOneOptionAndDefaultRendering()
|
|||
|
{
|
|||
|
var html = ReCaptcha.GetHtml(GetContext(), "PUBLIC_KEY", options: new { theme = "white" });
|
|||
|
UnitTestHelper.AssertEqualsIgnoreWhitespace(
|
|||
|
@"<script type=""text/javascript"">var RecaptchaOptions={""theme"":""white""};</script>" +
|
|||
|
@"<script src=""http://www.google.com/recaptcha/api/challenge?k=PUBLIC_KEY"" type=""text/javascript""></script>" +
|
|||
|
@"<noscript>" +
|
|||
|
@"<iframe frameborder=""0"" height=""300px"" src=""http://www.google.com/recaptcha/api/noscript?k=PUBLIC_KEY"" width=""500px""></iframe><br/><br/>" +
|
|||
|
@"<textarea cols=""40"" name=""recaptcha_challenge_field"" rows=""3""></textarea>" +
|
|||
|
@"<input name=""recaptcha_response_field"" type=""hidden"" value=""manual_challenge""/>" +
|
|||
|
@"</noscript>",
|
|||
|
html.ToString());
|
|||
|
XhtmlAssert.Validate1_0(html, addRoot: true);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ReCaptchaOptionsWhenMultipleOptionsAndDefaultRendering()
|
|||
|
{
|
|||
|
var html = ReCaptcha.GetHtml(GetContext(), "PUBLIC_KEY", options: new { theme = "white", tabindex = 5 });
|
|||
|
UnitTestHelper.AssertEqualsIgnoreWhitespace(
|
|||
|
@"<script type=""text/javascript"">var RecaptchaOptions={""theme"":""white"",""tabindex"":5};</script>" +
|
|||
|
@"<script src=""http://www.google.com/recaptcha/api/challenge?k=PUBLIC_KEY"" type=""text/javascript""></script>" +
|
|||
|
@"<noscript>" +
|
|||
|
@"<iframe frameborder=""0"" height=""300px"" src=""http://www.google.com/recaptcha/api/noscript?k=PUBLIC_KEY"" width=""500px""></iframe><br/><br/>" +
|
|||
|
@"<textarea cols=""40"" name=""recaptcha_challenge_field"" rows=""3""></textarea>" +
|
|||
|
@"<input name=""recaptcha_response_field"" type=""hidden"" value=""manual_challenge""/>" +
|
|||
|
@"</noscript>",
|
|||
|
html.ToString());
|
|||
|
XhtmlAssert.Validate1_0(html, addRoot: true);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ReCaptchaOptionsWhenMultipleOptionsFromDictionaryAndDefaultRendering()
|
|||
|
{
|
|||
|
// verifies that a dictionary will serialize the same as a projection
|
|||
|
var options = new Dictionary<string, object> { { "theme", "white" }, { "tabindex", 5 } };
|
|||
|
var html = ReCaptcha.GetHtml(GetContext(), "PUBLIC_KEY", options: options);
|
|||
|
UnitTestHelper.AssertEqualsIgnoreWhitespace(
|
|||
|
@"<script type=""text/javascript"">var RecaptchaOptions={""theme"":""white"",""tabindex"":5};</script>" +
|
|||
|
@"<script src=""http://www.google.com/recaptcha/api/challenge?k=PUBLIC_KEY"" type=""text/javascript""></script>" +
|
|||
|
@"<noscript>" +
|
|||
|
@"<iframe frameborder=""0"" height=""300px"" src=""http://www.google.com/recaptcha/api/noscript?k=PUBLIC_KEY"" width=""500px""></iframe><br/><br/>" +
|
|||
|
@"<textarea cols=""40"" name=""recaptcha_challenge_field"" rows=""3""></textarea>" +
|
|||
|
@"<input name=""recaptcha_response_field"" type=""hidden"" value=""manual_challenge""/>" +
|
|||
|
@"</noscript>",
|
|||
|
html.ToString());
|
|||
|
XhtmlAssert.Validate1_0(html, addRoot: true);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void RenderUsesLastError()
|
|||
|
{
|
|||
|
HttpContextBase context = GetContext();
|
|||
|
ReCaptcha.HandleValidateResponse(context, "false\nincorrect-captcha-sol");
|
|||
|
var html = ReCaptcha.GetHtml(context, "PUBLIC_KEY");
|
|||
|
UnitTestHelper.AssertEqualsIgnoreWhitespace(
|
|||
|
@"<script src=""http://www.google.com/recaptcha/api/challenge?k=PUBLIC_KEY&error=incorrect-captcha-sol"" type=""text/javascript""></script>" +
|
|||
|
@"<noscript>" +
|
|||
|
@"<iframe frameborder=""0"" height=""300px"" src=""http://www.google.com/recaptcha/api/noscript?k=PUBLIC_KEY"" width=""500px""></iframe><br/><br/>" +
|
|||
|
@"<textarea cols=""40"" name=""recaptcha_challenge_field"" rows=""3""></textarea>" +
|
|||
|
@"<input name=""recaptcha_response_field"" type=""hidden"" value=""manual_challenge""/>" +
|
|||
|
@"</noscript>",
|
|||
|
html.ToString());
|
|||
|
XhtmlAssert.Validate1_0(html, addRoot: true);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void RenderWhenConnectionIsSecure()
|
|||
|
{
|
|||
|
var html = ReCaptcha.GetHtml(GetContext(isSecure: true), "PUBLIC_KEY");
|
|||
|
UnitTestHelper.AssertEqualsIgnoreWhitespace(
|
|||
|
@"<script src=""https://www.google.com/recaptcha/api/challenge?k=PUBLIC_KEY"" type=""text/javascript""></script>" +
|
|||
|
@"<noscript>" +
|
|||
|
@"<iframe frameborder=""0"" height=""300px"" src=""https://www.google.com/recaptcha/api/noscript?k=PUBLIC_KEY"" width=""500px""></iframe><br/><br/>" +
|
|||
|
@"<textarea cols=""40"" name=""recaptcha_challenge_field"" rows=""3""></textarea>" +
|
|||
|
@"<input name=""recaptcha_response_field"" type=""hidden"" value=""manual_challenge""/>" +
|
|||
|
@"</noscript>",
|
|||
|
html.ToString());
|
|||
|
XhtmlAssert.Validate1_0(html, addRoot: true);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ValidateThrowsWhenRemoteAddressNotAvailable()
|
|||
|
{
|
|||
|
HttpContextBase context = GetContext();
|
|||
|
VirtualPathUtilityBase virtualPathUtility = GetVirtualPathUtility();
|
|||
|
context.Request.Form["recaptcha_challenge_field"] = "CHALLENGE";
|
|||
|
context.Request.Form["recaptcha_response_field"] = "RESPONSE";
|
|||
|
|
|||
|
Assert.Throws<InvalidOperationException>(() => { ReCaptcha.Validate(context, privateKey: "PRIVATE_KEY", virtualPathUtility: virtualPathUtility).ToString(); }, "The captcha cannot be validated because the remote address was not found in the request.");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ValidateReturnsFalseWhenChallengeNotPosted()
|
|||
|
{
|
|||
|
HttpContextBase context = GetContext();
|
|||
|
VirtualPathUtilityBase virtualPathUtility = GetVirtualPathUtility();
|
|||
|
context.Request.ServerVariables["REMOTE_ADDR"] = "127.0.0.1";
|
|||
|
|
|||
|
Assert.False(ReCaptcha.Validate(context, privateKey: "PRIVATE_KEY", virtualPathUtility: virtualPathUtility));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ValidatePostData()
|
|||
|
{
|
|||
|
HttpContextBase context = GetContext();
|
|||
|
VirtualPathUtilityBase virtualPathUtility = GetVirtualPathUtility();
|
|||
|
context.Request.ServerVariables["REMOTE_ADDR"] = "127.0.0.1";
|
|||
|
context.Request.Form["recaptcha_challenge_field"] = "CHALLENGE";
|
|||
|
context.Request.Form["recaptcha_response_field"] = "RESPONSE";
|
|||
|
|
|||
|
Assert.Equal("privatekey=PRIVATE_KEY&remoteip=127.0.0.1&challenge=CHALLENGE&response=RESPONSE",
|
|||
|
ReCaptcha.GetValidatePostData(context, "PRIVATE_KEY", virtualPathUtility));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ValidatePostDataWhenNoResponse()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
HttpContextBase context = GetContext();
|
|||
|
VirtualPathUtilityBase virtualPathUtility = GetVirtualPathUtility();
|
|||
|
context.Request.ServerVariables["REMOTE_ADDR"] = "127.0.0.1";
|
|||
|
context.Request.Form["recaptcha_challenge_field"] = "CHALLENGE";
|
|||
|
|
|||
|
// Act
|
|||
|
var validatePostData = ReCaptcha.GetValidatePostData(context, "PRIVATE_KEY", virtualPathUtility);
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Equal("privatekey=PRIVATE_KEY&remoteip=127.0.0.1&challenge=CHALLENGE&response=", validatePostData);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ValidateResponseReturnsFalseOnEmptyReCaptchaResponse()
|
|||
|
{
|
|||
|
HttpContextBase context = GetContext();
|
|||
|
Assert.False(ReCaptcha.HandleValidateResponse(context, ""));
|
|||
|
Assert.Equal(String.Empty, ReCaptcha.GetLastError(context));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ValidateResponseReturnsTrueOnSuccess()
|
|||
|
{
|
|||
|
HttpContextBase context = GetContext();
|
|||
|
Assert.True(ReCaptcha.HandleValidateResponse(context, "true\nsuccess"));
|
|||
|
Assert.Equal(String.Empty, ReCaptcha.GetLastError(context));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ValidateResponseReturnsFalseOnError()
|
|||
|
{
|
|||
|
HttpContextBase context = GetContext();
|
|||
|
Assert.False(ReCaptcha.HandleValidateResponse(context, "false\nincorrect-captcha-sol"));
|
|||
|
Assert.Equal("incorrect-captcha-sol", ReCaptcha.GetLastError(context));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ReCaptchaPrivateKeyThowsWhenSetToNull()
|
|||
|
{
|
|||
|
Assert.ThrowsArgumentNull(() => ReCaptcha.PrivateKey = null, "value");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ReCaptchaPrivateKeyUsesScopeStorage()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
var value = "value";
|
|||
|
|
|||
|
// Act
|
|||
|
ReCaptcha.PrivateKey = value;
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Equal(ReCaptcha.PrivateKey, value);
|
|||
|
Assert.Equal(ScopeStorage.CurrentScope[ReCaptcha._privateKey], value);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void PublicKeyThowsWhenSetToNull()
|
|||
|
{
|
|||
|
Assert.ThrowsArgumentNull(() => ReCaptcha.PublicKey = null, "value");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ReCaptchaPublicKeyUsesScopeStorage()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
var value = "value";
|
|||
|
|
|||
|
// Act
|
|||
|
ReCaptcha.PublicKey = value;
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Equal(ReCaptcha.PublicKey, value);
|
|||
|
Assert.Equal(ScopeStorage.CurrentScope[ReCaptcha._publicKey], value);
|
|||
|
}
|
|||
|
|
|||
|
private HttpContextBase GetContext(bool isSecure = false)
|
|||
|
{
|
|||
|
// mock HttpRequest
|
|||
|
Mock<HttpRequestBase> requestMock = new Mock<HttpRequestBase>();
|
|||
|
requestMock.Setup(request => request.IsSecureConnection).Returns(isSecure);
|
|||
|
requestMock.Setup(request => request.Form).Returns(new NameValueCollection());
|
|||
|
requestMock.Setup(request => request.ServerVariables).Returns(new NameValueCollection());
|
|||
|
|
|||
|
// mock HttpContext
|
|||
|
Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>();
|
|||
|
contextMock.Setup(context => context.Items).Returns(new Hashtable());
|
|||
|
contextMock.Setup(context => context.Request).Returns(requestMock.Object);
|
|||
|
return contextMock.Object;
|
|||
|
}
|
|||
|
|
|||
|
private static VirtualPathUtilityBase GetVirtualPathUtility()
|
|||
|
{
|
|||
|
var virtualPathUtility = new Mock<VirtualPathUtilityBase>();
|
|||
|
virtualPathUtility.Setup(c => c.ToAbsolute(It.IsAny<string>())).Returns<string>(_ => _);
|
|||
|
|
|||
|
return virtualPathUtility.Object;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|