Skip to content

Instantly share code, notes, and snippets.

@lwl5219
Last active November 20, 2019 04:05
Show Gist options
  • Save lwl5219/4d273ead9d56f295e5bc2efdaa37b591 to your computer and use it in GitHub Desktop.
Save lwl5219/4d273ead9d56f295e5bc2efdaa37b591 to your computer and use it in GitHub Desktop.
Http simulator for Unit Test. You can get more detail at https://haacked.com/archive/2005/06/11/simulating_httpcontext.aspx/
using System;
using System.Collections.Specialized;
using System.IO;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.SessionState;
namespace Subtext.TestLibrary {
public enum HttpVerb {
GET,
HEAD,
POST,
PUT,
DELETE,
}
/// <summary>
/// Useful class for simulating the HttpContext. This does not actually
/// make an HttpRequest, it merely simulates the state that your code
/// would be in "as if" handling a request. Thus the HttpContext.Current
/// property is populated.
/// </summary>
public class HttpSimulator : IDisposable {
private const string defaultPhysicalAppPath = @"c:\InetPub\wwwRoot\";
private StringBuilder builder;
private Uri _referer;
private NameValueCollection _formVars = new NameValueCollection();
private NameValueCollection _headers = new NameValueCollection();
private string appBinPath;
public HttpSimulator() : this("/", defaultPhysicalAppPath, defaultPhysicalAppPath) {
}
public HttpSimulator(string applicationPath) :
this(applicationPath, defaultPhysicalAppPath, defaultPhysicalAppPath) {
}
public HttpSimulator(string applicationPath, string physicalApplicationPath, string appBinPath) {
this.ApplicationPath = applicationPath;
this.PhysicalApplicationPath = physicalApplicationPath;
this.appBinPath = appBinPath;
}
/// <summary>
/// Sets up the HttpContext objects to simulate a GET request.
/// </summary>
/// <remarks>
/// Simulates a request to http://localhost/
/// </remarks>
public HttpSimulator SimulateRequest() {
return SimulateRequest(new Uri("http://localhost/"));
}
/// <summary>
/// Sets up the HttpContext objects to simulate a GET request.
/// </summary>
/// <param name="url"></param>
public HttpSimulator SimulateRequest(Uri url) {
return SimulateRequest(url, HttpVerb.GET);
}
/// <summary>
/// Sets up the HttpContext objects to simulate a request.
/// </summary>
/// <param name="url"></param>
/// <param name="httpVerb"></param>
public HttpSimulator SimulateRequest(Uri url, HttpVerb httpVerb) {
return SimulateRequest(url, httpVerb, null, null);
}
/// <summary>
/// Sets up the HttpContext objects to simulate a POST request.
/// </summary>
/// <param name="url"></param>
/// <param name="formVariables"></param>
public HttpSimulator SimulateRequest(Uri url, NameValueCollection formVariables) {
return SimulateRequest(url, HttpVerb.POST, formVariables, null);
}
/// <summary>
/// Sets up the HttpContext objects to simulate a POST request.
/// </summary>
/// <param name="url"></param>
/// <param name="formVariables"></param>
/// <param name="headers"></param>
public HttpSimulator SimulateRequest(Uri url, NameValueCollection formVariables, NameValueCollection headers) {
return SimulateRequest(url, HttpVerb.POST, formVariables, headers);
}
/// <summary>
/// Sets up the HttpContext objects to simulate a request.
/// </summary>
/// <param name="url"></param>
/// <param name="httpVerb"></param>
/// <param name="headers"></param>
public HttpSimulator SimulateRequest(Uri url, HttpVerb httpVerb, NameValueCollection headers) {
return SimulateRequest(url, httpVerb, null, headers);
}
/// <summary>
/// Sets up the HttpContext objects to simulate a request.
/// </summary>
/// <param name="url"></param>
/// <param name="httpVerb"></param>
/// <param name="formVariables"></param>
/// <param name="headers"></param>
protected virtual HttpSimulator SimulateRequest(Uri url, HttpVerb httpVerb, NameValueCollection formVariables,
NameValueCollection headers) {
HttpContext.Current = null;
ParseRequestUrl(url);
if (this.responseWriter == null) {
this.builder = new StringBuilder();
this.responseWriter = new StringWriter(builder);
}
SetHttpRuntimeInternals();
string query = ExtractQueryStringPart(url);
if (formVariables != null)
_formVars.Add(formVariables);
if (_formVars.Count > 0)
httpVerb = HttpVerb.POST; //Need to enforce this.
if (headers != null)
_headers.Add(headers);
this.workerRequest = new SimulatedHttpRequest(ApplicationPath, PhysicalApplicationPath, PhysicalPath, Page, query,
this.responseWriter, host, port, httpVerb.ToString());
this.workerRequest.Form.Add(_formVars);
this.workerRequest.Headers.Add(_headers);
if (_referer != null)
this.workerRequest.SetReferer(_referer);
InitializeSession();
InitializeApplication();
HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(""), new string[] { });
#region Console Debug INfo
Console.WriteLine("host: " + host);
Console.WriteLine("virtualDir: " + applicationPath);
Console.WriteLine("page: " + localPath);
Console.WriteLine("pathPartAfterApplicationPart: " + _page);
Console.WriteLine("appPhysicalDir: " + physicalApplicationPath);
Console.WriteLine("Request.Url.LocalPath: " + HttpContext.Current.Request.Url.LocalPath);
Console.WriteLine("Request.Url.Host: " + HttpContext.Current.Request.Url.Host);
Console.WriteLine("Request.FilePath: " + HttpContext.Current.Request.FilePath);
Console.WriteLine("Request.Path: " + HttpContext.Current.Request.Path);
Console.WriteLine("Request.RawUrl: " + HttpContext.Current.Request.RawUrl);
Console.WriteLine("Request.Url: " + HttpContext.Current.Request.Url);
Console.WriteLine("Request.Url.Port: " + HttpContext.Current.Request.Url.Port);
Console.WriteLine("Request.ApplicationPath: " + HttpContext.Current.Request.ApplicationPath);
Console.WriteLine("Request.PhysicalPath: " + HttpContext.Current.Request.PhysicalPath);
Console.WriteLine("User.Identity.Name: " + HttpContext.Current.User.Identity.Name);
Console.WriteLine("HttpRuntime.AppDomainAppVirtualPath: " + HttpRuntime.AppDomainAppVirtualPath);
Console.WriteLine("HostingEnvironment.ApplicationPhysicalPath: " + HostingEnvironment.ApplicationPhysicalPath);
Console.WriteLine("HostingEnvironment.ApplicationVirtualPath: " + HostingEnvironment.ApplicationVirtualPath);
#endregion
return this;
}
private static void InitializeApplication() {
Type appFactoryType =
Type.GetType(
"System.Web.HttpApplicationFactory, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
object appFactory = ReflectionHelper.GetStaticFieldValue<object>("_theApplicationFactory", appFactoryType);
ReflectionHelper.SetPrivateInstanceFieldValue("_state", appFactory, HttpContext.Current.Application);
}
private void InitializeSession() {
HttpContext.Current = new HttpContext(workerRequest);
HttpContext.Current.Items.Clear();
HttpSessionState session = (HttpSessionState) ReflectionHelper.Instantiate(typeof(HttpSessionState),
new Type[] {typeof(IHttpSessionState)}, new FakeHttpSessionState());
HttpContext.Current.Items.Add("AspSession", session);
}
public class FakeHttpSessionState : NameObjectCollectionBase, IHttpSessionState {
private string sessionID = Guid.NewGuid().ToString();
private int timeout = 30; //minutes
private bool isNewSession = true;
private int lcid;
private int codePage;
private HttpStaticObjectsCollection staticObjects = new HttpStaticObjectsCollection();
private object syncRoot = new Object();
///<summary>
///Ends the current session.
///</summary>
///
public void Abandon() {
BaseClear();
}
///<summary>
///Adds a new item to the session-state collection.
///</summary>
///
///<param name="name">The name of the item to add to the session-state collection. </param>
///<param name="value">The value of the item to add to the session-state collection. </param>
public void Add(string name, object value) {
BaseAdd(name, value);
}
///<summary>
///Deletes an item from the session-state item collection.
///</summary>
///
///<param name="name">The name of the item to delete from the session-state item collection. </param>
public void Remove(string name) {
BaseRemove(name);
}
///<summary>
///Deletes an item at a specified index from the session-state item collection.
///</summary>
///
///<param name="index">The index of the item to remove from the session-state collection. </param>
public void RemoveAt(int index) {
BaseRemoveAt(index);
}
///<summary>
///Clears all values from the session-state item collection.
///</summary>
///
public void Clear() {
BaseClear();
}
///<summary>
///Clears all values from the session-state item collection.
///</summary>
///
public void RemoveAll() {
BaseClear();
}
///<summary>
///Copies the collection of session-state item values to a one-dimensional array, starting at the specified index in the array.
///</summary>
///
///<param name="array">The <see cref="T:System.Array"></see> that receives the session values. </param>
///<param name="index">The index in array where copying starts. </param>
public void CopyTo(Array array, int index) {
throw new NotImplementedException();
}
///<summary>
///Gets the unique session identifier for the session.
///</summary>
///
///<returns>
///The session ID.
///</returns>
///
public string SessionID {
get { return sessionID; }
}
///<summary>
///Gets and sets the time-out period (in minutes) allowed between requests before the session-state provider terminates the session.
///</summary>
///
///<returns>
///The time-out period, in minutes.
///</returns>
///
public int Timeout {
get { return timeout; }
set { timeout = value; }
}
///<summary>
///Gets a value indicating whether the session was created with the current request.
///</summary>
///
///<returns>
///true if the session was created with the current request; otherwise, false.
///</returns>
///
public bool IsNewSession {
get { return isNewSession; }
}
///<summary>
///Gets the current session-state mode.
///</summary>
///
///<returns>
///One of the <see cref="T:System.Web.SessionState.SessionStateMode"></see> values.
///</returns>
///
public SessionStateMode Mode {
get { return SessionStateMode.InProc; }
}
///<summary>
///Gets a value indicating whether the session ID is embedded in the URL or stored in an HTTP cookie.
///</summary>
///
///<returns>
///true if the session is embedded in the URL; otherwise, false.
///</returns>
///
public bool IsCookieless {
get { return false; }
}
///<summary>
///Gets a value that indicates whether the application is configured for cookieless sessions.
///</summary>
///
///<returns>
///One of the <see cref="T:System.Web.HttpCookieMode"></see> values that indicate whether the application is configured for cookieless sessions. The default is <see cref="F:System.Web.HttpCookieMode.UseCookies"></see>.
///</returns>
///
public HttpCookieMode CookieMode {
get { return HttpCookieMode.UseCookies; }
}
///<summary>
///Gets or sets the locale identifier (LCID) of the current session.
///</summary>
///
///<returns>
///A <see cref="T:System.Globalization.CultureInfo"></see> instance that specifies the culture of the current session.
///</returns>
///
public int LCID {
get { return lcid; }
set { lcid = value; }
}
///<summary>
///Gets or sets the code-page identifier for the current session.
///</summary>
///
///<returns>
///The code-page identifier for the current session.
///</returns>
///
public int CodePage {
get { return codePage; }
set { codePage = value; }
}
///<summary>
///Gets a collection of objects declared by &lt;object Runat="Server" Scope="Session"/&gt; tags within the ASP.NET application file Global.asax.
///</summary>
///
///<returns>
///An <see cref="T:System.Web.HttpStaticObjectsCollection"></see> containing objects declared in the Global.asax file.
///</returns>
///
public HttpStaticObjectsCollection StaticObjects {
get { return staticObjects; }
}
///<summary>
///Gets or sets a session-state item value by name.
///</summary>
///
///<returns>
///The session-state item value specified in the name parameter.
///</returns>
///
///<param name="name">The key name of the session-state item value. </param>
public object this[string name] {
get { return BaseGet(name); }
set { BaseSet(name, value); }
}
///<summary>
///Gets or sets a session-state item value by numerical index.
///</summary>
///
///<returns>
///The session-state item value specified in the index parameter.
///</returns>
///
///<param name="index">The numerical index of the session-state item value. </param>
public object this[int index] {
get { return BaseGet(index); }
set { BaseSet(index, value); }
}
///<summary>
///Gets an object that can be used to synchronize access to the collection of session-state values.
///</summary>
///
///<returns>
///An object that can be used to synchronize access to the collection.
///</returns>
///
public object SyncRoot {
get { return syncRoot; }
}
///<summary>
///Gets a value indicating whether access to the collection of session-state values is synchronized (thread safe).
///</summary>
///<returns>
///true if access to the collection is synchronized (thread safe); otherwise, false.
///</returns>
///
public bool IsSynchronized {
get { return true; }
}
///<summary>
///Gets a value indicating whether the session is read-only.
///</summary>
///
///<returns>
///true if the session is read-only; otherwise, false.
///</returns>
///
bool IHttpSessionState.IsReadOnly {
get { return true; }
}
}
/// <summary>
/// Sets the referer for the request. Uses a fluent interface.
/// </summary>
/// <param name="referer"></param>
/// <returns></returns>
public HttpSimulator SetReferer(Uri referer) {
if (this.workerRequest != null)
this.workerRequest.SetReferer(referer);
this._referer = referer;
return this;
}
/// <summary>
/// Sets a form variable.
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
/// <returns></returns>
public HttpSimulator SetFormVariable(string name, string value) {
//TODO: Change this ordering requirement.
if (this.workerRequest != null)
throw new InvalidOperationException("Cannot set form variables after calling Simulate().");
_formVars.Add(name, value);
return this;
}
/// <summary>
/// Sets a header value.
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
/// <returns></returns>
public HttpSimulator SetHeader(string name, string value) {
//TODO: Change this ordering requirement.
if (this.workerRequest != null)
throw new InvalidOperationException("Cannot set headers after calling Simulate().");
_headers.Add(name, value);
return this;
}
private void ParseRequestUrl(Uri url) {
if (url == null)
return;
this.host = url.Host;
this.port = url.Port;
this.localPath = url.LocalPath;
this._page = StripPrecedingSlashes(RightAfter(url.LocalPath, ApplicationPath));
this.physicalPath = Path.Combine(this.physicalApplicationPath, this._page.Replace("/", @"\"));
}
static string RightAfter(string original, string search) {
if (search.Length > original.Length || search.Length == 0)
return original;
int searchIndex = original.IndexOf(search, 0, StringComparison.InvariantCultureIgnoreCase);
if (searchIndex < 0)
return original;
return original.Substring(original.IndexOf(search) + search.Length);
}
public string Host {
get { return this.host; }
}
private string host;
public string LocalPath {
get { return this.localPath; }
}
private string localPath;
public int Port {
get { return this.port; }
}
private int port;
/// <summary>
/// Portion of the URL after the application.
/// </summary>
public string Page {
get { return this._page; }
}
private string _page;
/// <summary>
/// The same thing as the IIS Virtual directory. It's
/// what gets returned by Request.ApplicationPath.
/// </summary>
public string ApplicationPath {
get { return this.applicationPath; }
set {
this.applicationPath = value ?? "/";
this.applicationPath = NormalizeSlashes(this.applicationPath);
}
}
private string applicationPath = "/";
/// <summary>
/// Physical path to the application (used for simulation purposes).
/// </summary>
public string PhysicalApplicationPath {
get { return this.physicalApplicationPath; }
set {
this.physicalApplicationPath = value ?? defaultPhysicalAppPath;
//strip trailing backslashes.
this.physicalApplicationPath = StripTrailingBackSlashes(this.physicalApplicationPath) + @"\";
}
}
private string physicalApplicationPath = defaultPhysicalAppPath;
/// <summary>
/// Physical path to the requested file (used for simulation purposes).
/// </summary>
public string PhysicalPath {
get { return this.physicalPath; }
}
private string physicalPath = defaultPhysicalAppPath;
public TextWriter ResponseWriter {
get { return this.responseWriter; }
set { this.responseWriter = value; }
}
/// <summary>
/// Returns the text from the response to the simulated request.
/// </summary>
public string ResponseText {
get { return (builder ?? new StringBuilder()).ToString(); }
}
private TextWriter responseWriter;
public SimulatedHttpRequest WorkerRequest {
get { return this.workerRequest; }
}
private SimulatedHttpRequest workerRequest;
private static string ExtractQueryStringPart(Uri url) {
string query = url.Query ?? string.Empty;
if (query.StartsWith("?"))
return query.Substring(1);
return query;
}
void SetHttpRuntimeInternals() {
//We cheat by using reflection.
// get singleton property value
HttpRuntime runtime = ReflectionHelper.GetStaticFieldValue<HttpRuntime>("_theRuntime", typeof(HttpRuntime));
// set app path property value
ReflectionHelper.SetPrivateInstanceFieldValue("_appDomainAppPath", runtime, PhysicalApplicationPath);
// set app virtual path property value
string vpathTypeName =
"System.Web.VirtualPath, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
object virtualPath =
ReflectionHelper.Instantiate(vpathTypeName, new Type[] {typeof(string)}, new object[] {ApplicationPath});
ReflectionHelper.SetPrivateInstanceFieldValue("_appDomainAppVPath", runtime, virtualPath);
// set codegen dir property value
ReflectionHelper.SetPrivateInstanceFieldValue("_codegenDir", runtime, PhysicalApplicationPath);
HostingEnvironment environment = GetHostingEnvironment();
ReflectionHelper.SetPrivateInstanceFieldValue("_appPhysicalPath", environment, PhysicalApplicationPath);
ReflectionHelper.SetPrivateInstanceFieldValue("_appVirtualPath", environment, virtualPath);
ReflectionHelper.SetPrivateInstanceFieldValue("_configMapPath", environment, new ConfigMapPath(this));
}
protected static HostingEnvironment GetHostingEnvironment() {
HostingEnvironment environment;
try {
environment = new HostingEnvironment();
}
catch (InvalidOperationException) {
//Shoot, we need to grab it via reflection.
environment =
ReflectionHelper.GetStaticFieldValue<HostingEnvironment>("_theHostingEnvironment",
typeof(HostingEnvironment));
}
return environment;
}
#region --- Text Manipulation Methods for slashes ---
protected static string NormalizeSlashes(string s) {
if (String.IsNullOrEmpty(s) || s == "/")
return "/";
s = s.Replace(@"\", "/");
//Reduce multiple slashes in row to single.
string normalized = Regex.Replace(s, "(/)/+", "$1");
//Strip left.
normalized = StripPrecedingSlashes(normalized);
//Strip right.
normalized = StripTrailingSlashes(normalized);
return "/" + normalized;
}
protected static string StripPrecedingSlashes(string s) {
return Regex.Replace(s, "^/*(.*)", "$1");
}
protected static string StripTrailingSlashes(string s) {
return Regex.Replace(s, "(.*)/*$", "$1", RegexOptions.RightToLeft);
}
protected static string StripTrailingBackSlashes(string s) {
if (String.IsNullOrEmpty(s))
return string.Empty;
return Regex.Replace(s, @"(.*)\\*$", "$1", RegexOptions.RightToLeft);
}
#endregion
internal class ConfigMapPath : IConfigMapPath {
private HttpSimulator _requestSimulation;
public ConfigMapPath(HttpSimulator simulation) {
_requestSimulation = simulation;
}
public string GetMachineConfigFilename() {
throw new NotImplementedException();
}
public string GetRootWebConfigFilename() {
throw new NotImplementedException();
}
public void GetPathConfigFilename(string siteID, string path, out string directory, out string baseName) {
throw new NotImplementedException();
}
public void GetDefaultSiteNameAndID(out string siteName, out string siteID) {
throw new NotImplementedException();
}
public void ResolveSiteArgument(string siteArgument, out string siteName, out string siteID) {
throw new NotImplementedException();
}
public string MapPath(string siteID, string path) {
if (path.ToLowerInvariant().Equals("/bin")) {
return _requestSimulation.appBinPath;
}
string page = StripPrecedingSlashes(RightAfter(path, _requestSimulation.ApplicationPath));
return Path.Combine(_requestSimulation.PhysicalApplicationPath, page.Replace("/", @"\"));
}
public string GetAppPathForPath(string siteID, string path) {
return _requestSimulation.ApplicationPath;
}
}
///<summary>
///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///</summary>
///<filterpriority>2</filterpriority>
public void Dispose() {
if (HttpContext.Current != null) {
HttpContext.Current = null;
}
}
}
}
using System;
using System.Collections.Specialized;
using System.Reflection;
using System.Web;
using System.Web.Hosting;
using MbUnit.Framework;
using Subtext.TestLibrary;
namespace UnitTests.SUbtext
{
[TestFixture]
public class HttpSimulatorTests
{
internal class TestHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string physicalPath = context.Request.MapPath("/MyHandler.ashx");
string username = context.Request.Form["username"];
string id = context.Request.QueryString["id"];
string referer = context.Request.UrlReferrer.ToString();
//Imagine, if you will, a bunch of complex interesting
//and fascinating logic here.
context.Response.Write(physicalPath + ":" + username + ":" + id + ":" + referer);
}
public bool IsReusable
{
get { return true; }
}
}
[Test]
public void CanGetSetSession()
{
using (new HttpSimulator("/", @"c:\inetpub\").SimulateRequest())
{
HttpContext.Current.Session["Test"] = "Success";
Assert.AreEqual("Success", HttpContext.Current.Session["Test"], "Was not able to retrieve session variable.");
}
}
[Test]
public void CanGetSetApplicationVariables()
{
using (new HttpSimulator("/", @"c:\inetpub\").SimulateRequest())
{
HttpContext.Current.Application["Test"] = "Success";
Assert.AreEqual("Success", HttpContext.Current.Application["Test"], "Was not able to retrieve application variable.");
}
}
[Test]
public void TestHttpHandlerWritesCorrectResponse()
{
using (HttpSimulator simulator = new HttpSimulator("/", @"c:\inetpub\"))
{
simulator.SetFormVariable("username", "phil")
.SetReferer(new Uri("http://example.com/1/"))
.SimulateRequest(new Uri("http://localhost/MyHandler.ashx?id=1234"));
TestHttpHandler handler = new TestHttpHandler();
handler.ProcessRequest(HttpContext.Current);
HttpContext.Current.Response.Flush();
string expected = @"c:\inetpub\MyHandler.ashx:phil:1234:http://example.com/1/";
Assert.AreEqual(expected, simulator.ResponseText, "The Expected Response is all wrong.");
} //HttpContext.Current is set to null again.
}
[Test]
public void CanDispose()
{
using (HttpSimulator simulator = new HttpSimulator())
{
simulator.SimulateRequest();
Assert.IsNotNull(HttpContext.Current);
}
Assert.IsNull(HttpContext.Current);
}
[RowTest]
[Row("http://localhost/Test/Default.aspx", "/Test", "/Test")]
[Row("http://localhost/Test/Default.aspx", "/Test/", "/Test")]
[Row("http://localhost/Test/Default.aspx", "//Test//", "/Test")]
[Row("http://localhost/Test/Subtest/Default.aspx", "/Test", "/Test")]
[Row("http://localhost/Test/Subtest/Default.aspx", "/Test/", "/Test")]
[Row("http://localhost/Test/Subtest/Default.aspx", "//Test//", "/Test")]
[Row("http://localhost/Test/Default.aspx", "", "/")]
[Row("http://localhost/Test/Default.aspx", "/", "/")]
[Row("http://localhost/Test/Default.aspx", null, "/")]
public void CanSetApplicationPathCorrectly(string url, string appPath, string expectedAppPath)
{
HttpSimulator simulator = new HttpSimulator(appPath, @"c:\inetpub\wwwroot\site1\test");
Assert.AreEqual(expectedAppPath, simulator.ApplicationPath);
simulator.SimulateRequest(new Uri(url));
Assert.AreEqual(expectedAppPath, HttpContext.Current.Request.ApplicationPath);
Assert.AreEqual(expectedAppPath, HttpRuntime.AppDomainAppVirtualPath);
Assert.AreEqual(expectedAppPath, HostingEnvironment.ApplicationVirtualPath);
}
[RowTest]
[Row("http://localhost/Test/default.aspx", "/Test", @"c:\projects\test", @"c:\projects\test\", @"c:\projects\test\default.aspx")]
[Row("http://localhost/Test/Subtest/default.aspx", "/Test", @"c:\projects\test", @"c:\projects\test\", @"c:\projects\test\Subtest\default.aspx")]
[Row("http://localhost/test/default.aspx", "/", @"c:\inetpub\wwwroot\", @"c:\inetpub\wwwroot\", @"c:\inetpub\wwwroot\test\default.aspx")]
[Row("http://localhost/test/default.aspx", "/", @"c:\inetpub\wwwroot", @"c:\inetpub\wwwroot\", @"c:\inetpub\wwwroot\test\default.aspx")]
public void CanSetAppPhysicalPathCorrectly(string url, string appPath, string appPhysicalPath, string expectedPhysicalAppPath, string expectedPhysicalPath)
{
HttpSimulator simulator = new HttpSimulator(appPath, appPhysicalPath);
Assert.AreEqual(expectedPhysicalAppPath, simulator.PhysicalApplicationPath);
simulator.SimulateRequest(new Uri(url), HttpVerb.GET);
Assert.AreEqual(expectedPhysicalPath, simulator.PhysicalPath);
Assert.AreEqual(expectedPhysicalAppPath, HttpRuntime.AppDomainAppPath);
Assert.AreEqual(expectedPhysicalAppPath, HostingEnvironment.ApplicationPhysicalPath);
Assert.AreEqual(expectedPhysicalPath, HttpContext.Current.Request.PhysicalPath);
}
[Test]
public void CanGetQueryString()
{
HttpSimulator simulator = new HttpSimulator();
simulator.SimulateRequest(new Uri("http://localhost/Test.aspx?param1=value1&param2=value2&param3=value3"));
for (int i = 1; i <= 3; i++)
Assert.AreEqual("value" + i, HttpContext.Current.Request.QueryString["param" + i], "Could not find query string field 'param{0}'", i);
simulator.SimulateRequest(new Uri("http://localhost/Test.aspx?param1=new-value1&param2=new-value2&param3=new-value3&param4=new-value4"));
for (int i = 1; i <= 4; i++)
Assert.AreEqual("new-value" + i, HttpContext.Current.Request.QueryString["param" + i], "Could not find query string field 'param{0}'", i);
simulator.SimulateRequest(new Uri("http://localhost/Test.aspx?"));
Assert.AreEqual(string.Empty, HttpContext.Current.Request.QueryString.ToString());
Assert.AreEqual(0, HttpContext.Current.Request.QueryString.Count);
simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"));
Assert.AreEqual(string.Empty, HttpContext.Current.Request.QueryString.ToString());
Assert.AreEqual(0, HttpContext.Current.Request.QueryString.Count);
simulator.SimulateRequest(new Uri("http://localhost/Test.aspx?param-name"));
Assert.AreEqual("param-name", HttpContext.Current.Request.QueryString.ToString());
Assert.AreEqual(1, HttpContext.Current.Request.QueryString.Count);
Assert.IsNull(HttpContext.Current.Request.QueryString["param-name"]);
}
[Test]
public void CanSimulateFormPost()
{
using (HttpSimulator simulator = new HttpSimulator())
{
NameValueCollection form = new NameValueCollection();
form.Add("Test1", "Value1");
form.Add("Test2", "Value2");
simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), form);
Assert.AreEqual("Value1", HttpContext.Current.Request.Form["Test1"]);
Assert.AreEqual("Value2", HttpContext.Current.Request.Form["Test2"]);
}
using (HttpSimulator simulator = new HttpSimulator())
{
simulator.SetFormVariable("Test1", "Value1")
.SetFormVariable("Test2", "Value2")
.SimulateRequest(new Uri("http://localhost/Test.aspx"));
Assert.AreEqual("Value1", HttpContext.Current.Request.Form["Test1"]);
Assert.AreEqual("Value2", HttpContext.Current.Request.Form["Test2"]);
}
}
[Test]
public void CanGetResponse()
{
HttpSimulator simulator = new HttpSimulator();
simulator.SimulateRequest();
HttpContext.Current.Response.Write("Hello World!");
HttpContext.Current.Response.Flush();
Assert.AreEqual("Hello World!", simulator.ResponseText);
}
[Test]
public void CanGetReferer()
{
HttpSimulator simulator = new HttpSimulator();
simulator.SetReferer(new Uri("http://example.com/Blah.aspx")).SimulateRequest();
Assert.AreEqual(new Uri("http://example.com/Blah.aspx"), HttpContext.Current.Request.UrlReferrer);
simulator = new HttpSimulator();
simulator.SimulateRequest().SetReferer(new Uri("http://x.example.com/Blah.aspx"));
Assert.AreEqual(new Uri("http://x.example.com/Blah.aspx"), HttpContext.Current.Request.UrlReferrer);
}
[RowTest]
[Row("http://localhost:60653/Test.aspx", null, null, "localhost", 60653, "/", "/Test.aspx", @"c:\InetPub\wwwRoot\")]
[Row("http://localhost:60653/Test.aspx?test=true", null, null, "localhost", 60653, "/", "/Test.aspx", @"c:\InetPub\wwwRoot\")]
[Row("http://localhost:60653/Test.aspx", "/", @"c:\InetPub\wwwRoot\", "localhost", 60653, "/", "/Test.aspx", @"c:\InetPub\wwwRoot\")]
[Row("http://localhost:60653/Test/Test.aspx", "/", @"c:\InetPub\wwwRoot\", "localhost", 60653, "/", "/Test/Test.aspx", @"c:\InetPub\wwwRoot\")]
[Row("http://localhost:60653/AppPath/Test.aspx", "/AppPath", @"c:\InetPub\wwwRoot\AppPath\", "localhost", 60653, "/AppPath", "/AppPath/Test.aspx", @"c:\InetPub\wwwRoot\AppPath\")]
[Row("http://localhost:60653/AppPath/Test.aspx", "/AppPath/", @"c:\InetPub\wwwRoot\AppPath\", "localhost", 60653, "/AppPath", "/AppPath/Test.aspx", @"c:\InetPub\wwwRoot\AppPath\")]
public void CanParseRequestUrl(string url, string appPath, string physicalPath, string expectedHost, int expectedPort, string expectedAppPath, string expectedPage, string expectedAppDomainAppPath)
{
HttpSimulator simulator = new HttpSimulator(appPath, physicalPath);
Assert.AreEqual(expectedAppPath, simulator.ApplicationPath);
Assert.AreEqual(expectedAppDomainAppPath, simulator.PhysicalApplicationPath);
}
[RowTest]
[Row("http://localhost/AppPath/default.aspx", "/AppPath", "/AppPath/default.aspx")]
[Row("http://localhost/AppPath/default.aspx", "/", "/AppPath/default.aspx")]
public void CanGetLocalPathCorrectly(string url, string appPath, string expectedLocalPath)
{
HttpSimulator simulator = new HttpSimulator(appPath, @"c:\inetpub\wwwroot\AppPath\");
simulator.SimulateRequest(new Uri(url));
Assert.AreEqual(expectedLocalPath, HttpContext.Current.Request.Path);
Assert.AreEqual(expectedLocalPath, HttpContext.Current.Request.Url.LocalPath);
}
[RowTest]
[Row("http://localhost:60653/Test.aspx", null, null, "localhost", 60653, "/", "/Test.aspx", @"c:\InetPub\wwwRoot\")]
[Row("http://localhost:60653/Test.aspx", "/", @"c:\InetPub\wwwRoot\", "localhost", 60653, "/", "/Test.aspx", @"c:\InetPub\wwwRoot\")]
[Row("http://localhost:60653/Test/Test.aspx", "/", @"c:\InetPub\wwwRoot\", "localhost", 60653, "/", "/Test/Test.aspx", @"c:\InetPub\wwwRoot\")]
[Row("http://localhost:60653/AppPath/Test.aspx", "/AppPath", @"c:\InetPub\wwwRoot\AppPath\", "localhost", 60653, "/AppPath", "/AppPath/Test.aspx", @"c:\InetPub\wwwRoot\AppPath\")]
[Row("http://localhost:60653/AppPath/Test.aspx", "/AppPath/", @"c:\InetPub\wwwRoot\AppPath\", "localhost", 60653, "/AppPath", "/AppPath/Test.aspx", @"c:\InetPub\wwwRoot\AppPath\")]
public void CanSimulateRequest(string url, string appPath, string physicalPath, string expectedHost, int expectedPort, string expectedAppPath, string expectedLocalPath, string expectedPhysicalPath)
{
HttpSimulator simulator = new HttpSimulator(appPath, physicalPath);
simulator.SimulateRequest(new Uri(url));
Assert.AreEqual(expectedHost, HttpContext.Current.Request.Url.Host);
Assert.AreEqual(expectedPort, HttpContext.Current.Request.Url.Port);
Assert.AreEqual(expectedAppPath, HttpContext.Current.Request.ApplicationPath);
Assert.AreEqual(expectedPhysicalPath, HttpContext.Current.Request.PhysicalApplicationPath);
Assert.AreEqual(expectedLocalPath, HttpContext.Current.Request.Url.LocalPath);
}
[RowTest]
[Row("/", "/", @"c:\inetpub\wwwroot\")]
[Row("/Test/Test.aspx", "/", @"c:\inetpub\wwwroot\Test\Test.aspx")]
[Row("/Test/Blah/Test.aspx", "/", @"c:\inetpub\wwwroot\Test\Blah\Test.aspx")]
[Row("/Test", "/Test", @"c:\inetpub\wwwroot")]
[Row("/Test/", "/Test", @"c:\inetpub\wwwroot\")]
public void CanMapPath(string virtualPath, string appPath, string expectedMapPath)
{
Uri url = new Uri("http://localhost/Test/Test.aspx");
HttpSimulator simulator = new HttpSimulator(appPath, @"c:\inetpub\wwwroot\");
simulator.SimulateRequest(url);
//Create a virtual path object.
object vpath = ReflectionHelper.Instantiate("System.Web.VirtualPath, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", new Type[] { typeof(string) }, virtualPath);
Assert.IsNotNull(vpath);
HostingEnvironment environment = HttpSimulatorTester.CallGetEnvironment();
string vpathString = ReflectionHelper.InvokeProperty<string>(vpath, "VirtualPathString");
object appVirtPath = ReflectionHelper.GetPrivateInstanceFieldValue<object>("_appVirtualPath", environment);
Assert.IsNotNull(appVirtPath);
Console.WriteLine("VPATH: " + vpath);
Console.WriteLine("App-VPATH: " + appVirtPath);
Console.WriteLine("vpath.VirtualPathString == '{0}'", vpathString);
string mapping = ReflectionHelper.InvokeNonPublicMethod<string>(typeof(HostingEnvironment), "GetVirtualPathToFileMapping", vpath);
Console.WriteLine("GetVirtualPathToFileMapping: --->{0}<---", (mapping ?? "{NULL}"));
object o = ReflectionHelper.GetPrivateInstanceFieldValue<object>("_configMapPath", environment);
Console.WriteLine("_configMapPath: {0}", o ?? "{null}");
string mappedPath = ReflectionHelper.InvokeNonPublicMethod<string>(environment, "MapPathActual", vpath, false);
Console.WriteLine("MAPPED: " + mappedPath);
Assert.AreEqual(expectedMapPath, HttpContext.Current.Request.MapPath(virtualPath));
}
[Test]
public void CanInstantiateVirtualPath()
{
Type virtualPathType = Type.GetType("System.Web.VirtualPath, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", true);
ConstructorInfo constructor = virtualPathType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);
Assert.IsNotNull(constructor);
}
[Test]
public void CanGetHostingEnvironment()
{
HostingEnvironment environment = HttpSimulatorTester.CallGetEnvironment();
Assert.IsNotNull(environment);
environment = HttpSimulatorTester.CallGetEnvironment();
Assert.IsNotNull(environment);
}
[RowTest]
[Row("/", "/")]
[Row("", "/")]
[Row("/test", "/test")]
[Row("test/", "/test")]
[Row("/test/", "/test")]
[Row("/test/////", "/test")]
[Row("////test/", "/test")]
[Row("/test/test////", "/test/test")]
[Row("/////test/test////", "/test/test")]
[Row("/////test///test////", "/test/test")]
public void CanNormalizeSlashes(string s, string expected)
{
Assert.AreEqual(expected, HttpSimulatorTester.CallNormalizeSlashes(s));
}
[Test]
public void CanStripTrailing()
{
Assert.AreEqual(@"c:\blah\blah2", HttpSimulatorTester.CallStripTrailingBackSlashes(@"c:\blah\blah2\"));
}
}
internal class HttpSimulatorTester : HttpSimulator
{
public static string CallNormalizeSlashes(string s)
{
return NormalizeSlashes(s);
}
public static string CallStripTrailingBackSlashes(string s)
{
return StripTrailingBackSlashes(s);
}
public static HostingEnvironment CallGetEnvironment()
{
return GetHostingEnvironment();
}
}
}
using System;
using System.Reflection;
namespace Subtext.TestLibrary
{
/// <summary>
/// Helper class to simplify common reflection tasks.
/// </summary>
public sealed class ReflectionHelper
{
private ReflectionHelper() {}
/// <summary>
/// Returns the value of the private member specified.
/// </summary>
/// <param name="fieldName">Name of the member.</param>
/// /// <param name="type">Type of the member.</param>
public static T GetStaticFieldValue<T>(string fieldName, Type type)
{
FieldInfo field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static);
if(field != null)
{
return (T)field.GetValue(type);
}
return default(T);
}
/// <summary>
/// Returns the value of the private member specified.
/// </summary>
/// <param name="fieldName">Name of the member.</param>
/// <param name="typeName"></param>
public static T GetStaticFieldValue<T>(string fieldName, string typeName)
{
Type type = Type.GetType(typeName, true);
FieldInfo field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static);
if (field != null)
{
return (T)field.GetValue(type);
}
return default(T);
}
/// <summary>
/// Sets the value of the private static member.
/// </summary>
/// <param name="fieldName"></param>
/// <param name="type"></param>
/// <param name="value"></param>
public static void SetStaticFieldValue<T>(string fieldName, Type type, T value)
{
FieldInfo field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static);
if (field == null)
throw new ArgumentException(string.Format("Could not find the private instance field '{0}'", fieldName));
field.SetValue(null, value);
}
/// <summary>
/// Sets the value of the private static member.
/// </summary>
/// <param name="fieldName"></param>
/// <param name="typeName"></param>
/// <param name="value"></param>
public static void SetStaticFieldValue<T>(string fieldName, string typeName, T value)
{
Type type = Type.GetType(typeName, true);
FieldInfo field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static);
if (field == null)
throw new ArgumentException(string.Format("Could not find the private instance field '{0}'", fieldName));
field.SetValue(null, value);
}
/// <summary>
/// Returns the value of the private member specified.
/// </summary>
/// <param name="fieldName">Name of the member.</param>
/// <param name="source">The object that contains the member.</param>
public static T GetPrivateInstanceFieldValue<T>(string fieldName, object source)
{
FieldInfo field = source.GetType().GetField(fieldName, BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
if(field != null)
{
return (T)field.GetValue(source);
}
return default(T);
}
/// <summary>
/// Returns the value of the private member specified.
/// </summary>
/// <param name="memberName">Name of the member.</param>
/// <param name="source">The object that contains the member.</param>
/// <param name="value">The value to set the member to.</param>
public static void SetPrivateInstanceFieldValue(string memberName, object source, object value)
{
FieldInfo field = source.GetType().GetField(memberName, BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
if (field == null)
throw new ArgumentException(string.Format("Could not find the private instance field '{0}'",memberName));
field.SetValue(source, value);
}
public static object Instantiate(string typeName)
{
return Instantiate(typeName, null, null);
}
public static object Instantiate(string typeName, Type[] constructorArgumentTypes, params object[] constructorParameterValues)
{
return Instantiate(Type.GetType(typeName, true), constructorArgumentTypes, constructorParameterValues);
}
public static object Instantiate(Type type, Type[] constructorArgumentTypes, params object[] constructorParameterValues)
{
ConstructorInfo constructor = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, constructorArgumentTypes, null);
return constructor.Invoke(constructorParameterValues);
}
/// <summary>
/// Invokes a non-public static method.
/// </summary>
/// <typeparam name="TReturn"></typeparam>
/// <param name="type"></param>
/// <param name="methodName"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static TReturn InvokeNonPublicMethod<TReturn>(Type type, string methodName, params object[] parameters)
{
Type[] paramTypes = Array.ConvertAll(parameters, new Converter<object, Type>(delegate(object o) { return o.GetType(); }));
MethodInfo method = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static, null, paramTypes, null);
if (method == null)
throw new ArgumentException(string.Format("Could not find a method with the name '{0}'", methodName), "method");
return (TReturn)method.Invoke(null, parameters);
}
public static TReturn InvokeNonPublicMethod<TReturn>(object source, string methodName, params object[] parameters)
{
Type[] paramTypes = Array.ConvertAll(parameters, new Converter<object, Type>(delegate(object o) { return o.GetType(); }));
MethodInfo method = source.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance, null, paramTypes, null);
if (method == null)
throw new ArgumentException(string.Format("Could not find a method with the name '{0}'", methodName), "method");
return (TReturn)method.Invoke(source, parameters);
}
public static TReturn InvokeProperty<TReturn>(object source, string propertyName)
{
PropertyInfo propertyInfo = source.GetType().GetProperty(propertyName);
if (propertyInfo == null)
throw new ArgumentException(string.Format("Could not find a propertyName with the name '{0}'", propertyName), "propertyName");
return (TReturn)propertyInfo.GetValue(source, null);
}
public static TReturn InvokeNonPublicProperty<TReturn>(object source, string propertyName)
{
PropertyInfo propertyInfo = source.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance, null, typeof(TReturn), new Type[0], null);
if (propertyInfo == null)
throw new ArgumentException(string.Format("Could not find a propertyName with the name '{0}'", propertyName), "propertyName");
return (TReturn) propertyInfo.GetValue(source, null);
}
public static object InvokeNonPublicProperty(object source, string propertyName)
{
PropertyInfo propertyInfo = source.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);
if (propertyInfo == null)
throw new ArgumentException(string.Format("Could not find a propertyName with the name '{0}'", propertyName), "propertyName");
return propertyInfo.GetValue(source, null);
}
}
}
#region Disclaimer/Info
///////////////////////////////////////////////////////////////////////////////////////////////////
// Subtext WebLog
//
// Subtext is an open source weblog system that is a fork of the .TEXT
// weblog system.
//
// For updated news and information please visit http://subtextproject.com/
// Subtext is hosted at SourceForge at http://sourceforge.net/projects/subtext
// The development mailing list is at [email protected]
//
// This project is licensed under the BSD license. See the License.txt file for more information.
///////////////////////////////////////////////////////////////////////////////////////////////////
#endregion
using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using System.Web.Hosting;
namespace Subtext.TestLibrary
{
/// <summary>
/// Used to simulate an HttpRequest.
/// </summary>
public class SimulatedHttpRequest : SimpleWorkerRequest
{
Uri _referer;
string _host;
string _verb;
int _port;
string _physicalFilePath;
/// <summary>
/// Creates a new <see cref="SimulatedHttpRequest"/> instance.
/// </summary>
/// <param name="applicationPath">App virtual dir.</param>
/// <param name="physicalAppPath">Physical Path to the app.</param>
/// <param name="physicalFilePath">Physical Path to the file.</param>
/// <param name="page">The Part of the URL after the application.</param>
/// <param name="query">Query.</param>
/// <param name="output">Output.</param>
/// <param name="host">Host.</param>
/// <param name="port">Port to request.</param>
/// <param name="verb">The HTTP Verb to use.</param>
public SimulatedHttpRequest(string applicationPath, string physicalAppPath, string physicalFilePath, string page, string query, TextWriter output, string host, int port, string verb) : base(applicationPath, physicalAppPath, page, query, output)
{
if (host == null)
throw new ArgumentNullException("host", "Host cannot be null.");
if(host.Length == 0)
throw new ArgumentException("Host cannot be empty.", "host");
if (applicationPath == null)
throw new ArgumentNullException("applicationPath", "Can't create a request with a null application path. Try empty string.");
_host = host;
_verb = verb;
_port = port;
_physicalFilePath = physicalFilePath;
}
internal void SetReferer(Uri referer)
{
_referer = referer;
}
/// <summary>
/// Returns the specified member of the request header.
/// </summary>
/// <returns>
/// The HTTP verb returned in the request
/// header.
/// </returns>
public override string GetHttpVerbName()
{
return _verb;
}
/// <summary>
/// Gets the name of the server.
/// </summary>
/// <returns></returns>
public override string GetServerName()
{
return _host;
}
public override int GetLocalPort()
{
return this._port;
}
/// <summary>
/// Gets the headers.
/// </summary>
/// <value>The headers.</value>
public NameValueCollection Headers
{
get
{
return this.headers;
}
}
private NameValueCollection headers = new NameValueCollection();
/// <summary>
/// Gets the format exception.
/// </summary>
/// <value>The format exception.</value>
public NameValueCollection Form
{
get
{
return formVariables;
}
}
private NameValueCollection formVariables = new NameValueCollection();
/// <summary>
/// Get all nonstandard HTTP header name-value pairs.
/// </summary>
/// <returns>An array of header name-value pairs.</returns>
public override string[][] GetUnknownRequestHeaders()
{
if(this.headers == null || this.headers.Count == 0)
{
return null;
}
string[][] headersArray = new string[this.headers.Count][];
for(int i = 0; i < this.headers.Count; i++)
{
headersArray[i] = new string[2];
headersArray[i][0] = this.headers.Keys[i];
headersArray[i][1] = this.headers[i];
}
return headersArray;
}
public override string GetKnownRequestHeader(int index)
{
if (index == 0x24)
return _referer == null ? string.Empty : _referer.ToString();
if (index == 12 && this._verb == "POST")
return "application/x-www-form-urlencoded";
return base.GetKnownRequestHeader(index);
}
/// <summary>
/// Returns the virtual path to the currently executing
/// server application.
/// </summary>
/// <returns>
/// The virtual path of the current application.
/// </returns>
public override string GetAppPath()
{
string appPath = base.GetAppPath();
return appPath;
}
public override string GetAppPathTranslated()
{
string path = base.GetAppPathTranslated();
return path;
}
public override string GetUriPath()
{
string uriPath = base.GetUriPath();
return uriPath;
}
public override string GetFilePathTranslated()
{
return _physicalFilePath;
}
/// <summary>
/// Reads request data from the client (when not preloaded).
/// </summary>
/// <returns>The number of bytes read.</returns>
public override byte[] GetPreloadedEntityBody()
{
string formText = string.Empty;
foreach(string key in this.formVariables.Keys)
{
formText += string.Format("{0}={1}&", key, this.formVariables[key]);
}
return Encoding.UTF8.GetBytes(formText);
}
/// <summary>
/// Returns a value indicating whether all request data
/// is available and no further reads from the client are required.
/// </summary>
/// <returns>
/// <see langword="true"/> if all request data is available; otherwise,
/// <see langword="false"/>.
/// </returns>
public override bool IsEntireEntityBodyIsPreloaded()
{
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment