Add support for generating baseline output files while testing

- baselines include both expected output and design-time line mappings
- controlled by GENERATE_BASELINES
 - assertions related to file content are not checked in this mode
- add design-time test of Basic.cshtml to `MvcRazorHostTest`
- regenerate all files to avoid BOM and blank line noise in future PRs
 - update out-of-date design-time Basic.cs file

nits:
- make a few variable names more consistent
- make `Assembly` fields `static`
- remove unused `_resourcesAssembly` field from `ErrorPageTests`
- remove `ResourceHelpers` which was specific to functional tests
This commit is contained in:
Doug Bunting 2015-05-31 18:52:35 -07:00
parent 386562c269
commit ffd1dc1fb0
63 changed files with 650 additions and 282 deletions

View File

@ -20,14 +20,15 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public class BasicTests
{
private const string SiteName = nameof(BasicWebSite);
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new Startup().ConfigureServices;
// Some tests require comparing the actual response body against an expected response baseline
// so they require a reference to the assembly on which the resources are located, in order to
// make the tests less verbose, we get a reference to the assembly with the resources and we
// use it on all the rest of the tests.
private readonly Assembly _resourcesAssembly = typeof(BasicTests).GetTypeInfo().Assembly;
private static readonly Assembly _resourcesAssembly = typeof(BasicTests).GetTypeInfo().Assembly;
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new Startup().ConfigureServices;
[Theory]
[InlineData("http://localhost/")]
@ -39,13 +40,11 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8");
// The K runtime compiles every file under compiler/resources as a resource at runtime with the same name
// as the file name, in order to update a baseline you just need to change the file in that folder.
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync("compiler/resources/BasicWebSite.Home.Index.html");
var outputFile = "compiler/resources/BasicWebSite.Home.Index.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
// The host is not important as everything runs in memory and tests are isolated from each other.
var response = await client.GetAsync(url);
var responseContent = await response.Content.ReadAsStringAsync();
@ -53,7 +52,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]
@ -62,9 +66,10 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync("compiler/resources/BasicWebSite.Home.PlainView.html");
var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8");
var outputFile = "compiler/resources/BasicWebSite.Home.PlainView.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
var response = await client.GetAsync("http://localhost/Home/PlainView");
@ -73,7 +78,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]
@ -82,8 +92,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(
"compiler/resources/BasicWebSite.Home.ViewWithPrefixedAttributeValue.html");
var outputFile = "compiler/resources/BasicWebSite.Home.ViewWithPrefixedAttributeValue.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
var response = await client.GetAsync("http://localhost/Home/ViewWithPrefixedAttributeValue");
@ -91,7 +102,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]

View File

@ -4,7 +4,6 @@
using System;
using System.Net;
using System.Net.Http.Headers;
using System.Reflection;
using System.Threading.Tasks;
using ErrorPageMiddlewareWebSite;
using Microsoft.AspNet.Builder;
@ -22,8 +21,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new Startup().ConfigureServices;
private readonly Assembly _resourcesAssembly = typeof(ErrorPageTests).GetTypeInfo().Assembly;
[Theory]
[InlineData("CompilationFailure", "Cannot implicitly convert type &#x27;int&#x27; to &#x27;string&#x27;")]
[InlineData("ParserError", "The code block is missing a closing &quot;}&quot; character. Make sure you " +

View File

@ -15,15 +15,15 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public class LinkGenerationTests
{
private const string SiteName = nameof(BasicWebSite);
private readonly Action<IApplicationBuilder> _app = new BasicWebSite.Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new BasicWebSite.Startup().ConfigureServices;
// Some tests require comparing the actual response body against an expected response baseline
// so they require a reference to the assembly on which the resources are located, in order to
// make the tests less verbose, we get a reference to the assembly with the resources and we
// use it on all the rest of the tests.
private readonly Assembly _resourcesAssembly = typeof(LinkGenerationTests).GetTypeInfo().Assembly;
private static readonly Assembly _resourcesAssembly = typeof(LinkGenerationTests).GetTypeInfo().Assembly;
private readonly Action<IApplicationBuilder> _app = new BasicWebSite.Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new BasicWebSite.Startup().ConfigureServices;
[Theory]
[InlineData("http://pingüino/Home/RedirectToActionReturningTaskAction", "/Home/ActionReturningTask")]
@ -55,13 +55,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8");
var expectedContent = await _resourcesAssembly
.ReadResourceAsStringAsync("compiler/resources/BasicWebSite.Home.ActionLinkView.html");
var outputFile = "compiler/resources/BasicWebSite.Home.ActionLinkView.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
// The host is not important as everything runs in memory and tests are isolated from each other.
var response = await client.GetAsync("http://localhost/Home/ActionLinkView");
var responseContent = await response.Content.ReadAsStringAsync();
@ -69,7 +68,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
}
}

View File

@ -13,7 +13,6 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.Framework.DependencyInjection;
using ModelBindingWebSite.Controllers;
using ModelBindingWebSite.Models;
using ModelBindingWebSite.ViewModels;
using Newtonsoft.Json;
@ -24,6 +23,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public class ModelBindingTest
{
private const string SiteName = nameof(ModelBindingWebSite);
private static readonly Assembly _assembly = typeof(ModelBindingTest).GetTypeInfo().Assembly;
private readonly Action<IApplicationBuilder> _app = new ModelBindingWebSite.Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new ModelBindingWebSite.Startup().ConfigureServices;
@ -1383,10 +1384,10 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public async Task UpdateDealerVehicle_PopulatesPropertyErrorsInViews()
{
// Arrange
var expectedContent = await GetType().GetTypeInfo().Assembly.ReadResourceAsStringAsync(
"compiler/resources/UpdateDealerVehicle_PopulatesPropertyErrorsInViews.txt");
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var outputFile = "compiler/resources/UpdateDealerVehicle_PopulatesPropertyErrorsInViews.txt";
var expectedContent = await ResourceFile.ReadResourceAsync(_assembly, outputFile, sourceFile: false);
var postedContent = new
{
Year = 9001,
@ -1406,18 +1407,23 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal(expectedContent, body);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]
public async Task UpdateDealerVehicle_PopulatesValidationSummary()
{
// Arrange
var expectedContent = await GetType().GetTypeInfo().Assembly.ReadResourceAsStringAsync(
"compiler/resources/UpdateDealerVehicle_PopulatesValidationSummary.txt");
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var outputFile = "compiler/resources/UpdateDealerVehicle_PopulatesValidationSummary.txt";
var expectedContent = await ResourceFile.ReadResourceAsync(_assembly, outputFile, sourceFile: false);
var postedContent = new
{
Year = 2013,
@ -1437,18 +1443,23 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal(expectedContent, body);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]
public async Task UpdateDealerVehicle_UsesDefaultValuesForOptionalProperties()
{
// Arrange
var expectedContent = await GetType().GetTypeInfo().Assembly.ReadResourceAsStringAsync(
"compiler/resources/UpdateDealerVehicle_UpdateSuccessful.txt");
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var outputFile = "compiler/resources/UpdateDealerVehicle_UpdateSuccessful.txt";
var expectedContent = await ResourceFile.ReadResourceAsync(_assembly, outputFile, sourceFile: false);
var postedContent = new
{
Year = 2013,
@ -1468,8 +1479,13 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal(expectedContent, body);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]
@ -1603,10 +1619,10 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public async Task HtmlHelper_DisplayFor_ShowsPropertiesInModelMetadataOrder()
{
// Arrange
var expectedContent = await GetType().GetTypeInfo().Assembly.ReadResourceAsStringAsync(
"compiler/resources/ModelBindingWebSite.Vehicle.Details.html");
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var outputFile = "compiler/resources/ModelBindingWebSite.Vehicle.Details.html";
var expectedContent = await ResourceFile.ReadResourceAsync(_assembly, outputFile, sourceFile: false);
var url = "http://localhost/vehicles/42";
// Act
@ -1615,18 +1631,22 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal(expectedContent, body);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]
public async Task HtmlHelper_EditorFor_ShowsPropertiesInModelMetadataOrder()
{
// Arrange
var expectedContent = await GetType().GetTypeInfo().Assembly.ReadResourceAsStringAsync(
"compiler/resources/ModelBindingWebSite.Vehicle.Edit.html");
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var outputFile = "compiler/resources/ModelBindingWebSite.Vehicle.Edit.html";
var expectedContent = await ResourceFile.ReadResourceAsync(_assembly, outputFile, sourceFile: false);
var url = "http://localhost/vehicles/42/edit";
// Act
@ -1635,18 +1655,22 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal(expectedContent, body);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]
public async Task HtmlHelper_EditorFor_ShowsPropertiesAndErrorsInModelMetadataOrder()
{
// Arrange
var expectedContent = await GetType().GetTypeInfo().Assembly.ReadResourceAsStringAsync(
"compiler/resources/ModelBindingWebSite.Vehicle.Edit.Invalid.html");
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var outputFile = "compiler/resources/ModelBindingWebSite.Vehicle.Edit.Invalid.html";
var expectedContent = await ResourceFile.ReadResourceAsync(_assembly, outputFile, sourceFile: false);
var url = "http://localhost/vehicles/42/edit";
var contentDictionary = new Dictionary<string, string>
{
@ -1674,8 +1698,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal(expectedContent, body);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]

View File

@ -21,9 +21,10 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public class MvcTagHelpersTest
{
private const string SiteName = nameof(MvcTagHelpersWebSite);
private static readonly Assembly _resourcesAssembly = typeof(MvcTagHelpersTest).GetTypeInfo().Assembly;
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new Startup().ConfigureServices;
private static readonly Assembly _resourcesAssembly = typeof(MvcTagHelpersTest).GetTypeInfo().Assembly;
[Theory]
[InlineData("Index", null)]
@ -57,11 +58,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8");
// The K runtime compiles every file under compiler/resources as a resource at runtime with the same name
// as the file name, in order to update a baseline you just need to change the file in that folder.
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(
"compiler/resources/MvcTagHelpersWebSite.MvcTagHelper_Home." + action + ".html");
var outputFile = "compiler/resources/MvcTagHelpersWebSite.MvcTagHelper_Home." + action + ".html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
// The host is not important as everything runs in memory and tests are isolated from each other.
@ -72,13 +71,27 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
if (antiForgeryPath != null)
responseContent = responseContent.Trim();
if (antiForgeryPath == null)
{
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent.Trim(), responseContent);
#endif
}
else
{
var forgeryToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(responseContent, antiForgeryPath);
#if GENERATE_BASELINES
// Reverse usual substitution and insert a format item into the new file content.
responseContent = responseContent.Replace(forgeryToken, "{0}");
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
expectedContent = string.Format(expectedContent, forgeryToken);
Assert.Equal(expectedContent.Trim(), responseContent);
#endif
}
Assert.Equal(expectedContent.Trim(), responseContent.Trim());
}
[Theory]
@ -101,11 +114,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
});
var client = server.CreateClient();
var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8");
// The K runtime compiles every file under compiler/resources as a resource at runtime with the same name
// as the file name, in order to update a baseline you just need to change the file in that folder.
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(
"compiler/resources/MvcTagHelpersWebSite.MvcTagHelper_Home." + action + ".Encoded.html");
var outputFile = "compiler/resources/MvcTagHelpersWebSite.MvcTagHelper_Home." + action + ".Encoded.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
// The host is not important as everything runs in memory and tests are isolated from each other.
@ -116,13 +127,27 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
if (antiForgeryPath != null)
responseContent = responseContent.Trim();
if (antiForgeryPath == null)
{
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent.Trim(), responseContent);
#endif
}
else
{
var forgeryToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(responseContent, antiForgeryPath);
#if GENERATE_BASELINES
// Reverse usual substitution and insert a format item into the new file content.
responseContent = responseContent.Replace(forgeryToken, "{0}");
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
expectedContent = string.Format(expectedContent, forgeryToken);
Assert.Equal(expectedContent.Trim(), responseContent);
#endif
}
Assert.Equal(expectedContent.Trim(), responseContent.Trim());
}
[Fact]
@ -131,8 +156,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(
"compiler/resources/MvcTagHelpersWebSite.MvcTagHelper_Customer.Index.html");
var outputFile = "compiler/resources/MvcTagHelpersWebSite.MvcTagHelper_Customer.Index.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Customer/MvcTagHelper_Customer");
var nameValueCollection = new List<KeyValuePair<string, string>>
@ -152,9 +178,18 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var forgeryToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(responseContent, "Customer/MvcTagHelper_Customer");
responseContent = responseContent.Trim();
var forgeryToken =
AntiForgeryTestHelper.RetrieveAntiForgeryToken(responseContent, "Customer/MvcTagHelper_Customer");
#if GENERATE_BASELINES
// Reverse usual substitution and insert a format item into the new file content.
responseContent = responseContent.Replace(forgeryToken, "{0}");
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
expectedContent = string.Format(expectedContent, forgeryToken);
Assert.Equal(expectedContent.Trim(), responseContent.Trim());
Assert.Equal(expectedContent.Trim(), responseContent);
#endif
}
[Fact]
@ -168,6 +203,16 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
client.BaseAddress = new Uri("http://localhost");
client.DefaultRequestHeaders.Add("Locale", "North");
var outputFile1 = assertFile + "1.txt";
var expected1 =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile1, sourceFile: false);
var outputFile2 = assertFile + "2.txt";
var expected2 =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile2, sourceFile: false);
var outputFile3 = assertFile + "3.txt";
var expected3 =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile3, sourceFile: false);
// Act - 1
// Verify that content gets cached based on vary-by-params
var targetUrl = "/catalog?categoryId=1&correlationid=1";
@ -175,10 +220,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var response2 = await client.GetStringAsync(targetUrl);
// Assert - 1
var expected1 = await _resourcesAssembly.ReadResourceAsStringAsync(assertFile + "1.txt");
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile1, expected1, response1.Trim());
#else
Assert.Equal(expected1, response1.Trim());
Assert.Equal(expected1, response2.Trim());
#endif
// Act - 2
// Verify content gets changed in partials when one of the vary by parameters is changed
@ -187,10 +234,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var response4 = await client.GetStringAsync(targetUrl);
// Assert - 2
var expected2 = await _resourcesAssembly.ReadResourceAsStringAsync(assertFile + "2.txt");
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile2, expected2, response3.Trim());
#else
Assert.Equal(expected2, response3.Trim());
Assert.Equal(expected2, response4.Trim());
#endif
// Act - 3
// Verify content gets changed in a View Component when the Vary-by-header parameters is changed
@ -202,10 +251,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var response6 = await client.GetStringAsync(targetUrl);
// Assert - 3
var expected3 = await _resourcesAssembly.ReadResourceAsStringAsync(assertFile + "3.txt");
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile3, expected3, response5.Trim());
#else
Assert.Equal(expected3, response5.Trim());
Assert.Equal(expected3, response6.Trim());
#endif
}
[Fact]
@ -424,26 +475,36 @@ Products: Laptops (3)";
var client = server.CreateClient();
var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8");
// The K runtime compiles every file under compiler/resources as a resource at runtime with the same name
// as the file name, in order to update a baseline you just need to change the file in that folder.
var resourceName = string.Format(
var outputFile = string.Format(
"compiler/resources/MvcTagHelpersWebSite.MvcTagHelper_Home.Form.Options.AntiForgery.{0}.html",
optionsAntiForgery?.ToString() ?? "null"
);
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(resourceName);
optionsAntiForgery?.ToString() ?? "null");
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
// The host is not important as everything runs in memory and tests are isolated from each other.
var response = await client.GetAsync("http://localhost/MvcTagHelper_Home/Form");
var responseContent = await response.Content.ReadAsStringAsync();
var forgeryTokens = AntiForgeryTestHelper.RetrieveAntiForgeryTokens(responseContent);
expectedContent = string.Format(expectedContent, forgeryTokens.ToArray());
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
Assert.Equal(expectedContent.Trim(), responseContent.Trim());
responseContent = responseContent.Trim();
var forgeryTokens = AntiForgeryTestHelper.RetrieveAntiForgeryTokens(responseContent).ToArray();
#if GENERATE_BASELINES
// Reverse usual substitutions and insert format items into the new file content.
for (var index = 0; index < forgeryTokens.Length; index++)
{
responseContent = responseContent.Replace(forgeryTokens[index], $"{{{ index }}}");
}
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
expectedContent = string.Format(expectedContent, forgeryTokens);
Assert.Equal(expectedContent.Trim(), responseContent);
#endif
}
}
}

View File

@ -18,6 +18,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
private const string SiteName = nameof(ValidationWebSite);
private static readonly Assembly _resourcesAssembly =
typeof(RemoteAttributeValidationTest).GetTypeInfo().Assembly;
private readonly Action<IApplicationBuilder> _app = new ValidationWebSite.Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new ValidationWebSite.Startup().ConfigureServices;
@ -29,8 +30,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(
"compiler/resources/ValidationWebSite." + areaName + ".RemoteAttribute_Home.Create.html");
var outputFile = "compiler/resources/ValidationWebSite." + areaName + ".RemoteAttribute_Home.Create.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
var url = "http://localhost" + pathSegment + "/RemoteAttribute_Home/Create";
// Act
@ -40,8 +42,13 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("text/html", response.Content.Headers.ContentType.MediaType);
Assert.Equal("utf-8", response.Content.Headers.ContentType.CharSet);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Theory]

View File

@ -1,28 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.FunctionalTests
{
// This class contains helper methods for reading resources from a given assembly in order
// to make tests that require comparing against baseline files embedded as resources less
// verbose.
public static class ResourceHelpers
{
public static async Task<string> ReadResourceAsStringAsync(this Assembly assembly, string resourceName)
{
resourceName = assembly.GetName().Name + "." + resourceName.Replace('/', '.');
using (var resourceStream = assembly.GetManifestResourceStream(resourceName))
{
using (var streamReader = new StreamReader(resourceStream))
{
return await streamReader.ReadToEndAsync();
}
}
}
}
}

View File

@ -18,14 +18,15 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public class TagHelpersTests
{
private const string SiteName = nameof(TagHelpersWebSite);
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new Startup().ConfigureServices;
// Some tests require comparing the actual response body against an expected response baseline
// so they require a reference to the assembly on which the resources are located, in order to
// make the tests less verbose, we get a reference to the assembly with the resources and we
// use it on all the rest of the tests.
private readonly Assembly _resourcesAssembly = typeof(TagHelpersTests).GetTypeInfo().Assembly;
private static readonly Assembly _resourcesAssembly = typeof(TagHelpersTests).GetTypeInfo().Assembly;
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new Startup().ConfigureServices;
[Theory]
[InlineData("Index")]
@ -37,22 +38,24 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8");
// The K runtime compiles every file under compiler/resources as a resource at runtime with the same name
// as the file name, in order to update a baseline you just need to change the file in that folder.
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(
"compiler/resources/TagHelpersWebSite.Home." + action + ".html");
var outputFile = "compiler/resources/TagHelpersWebSite.Home." + action + ".html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
// The host is not important as everything runs in memory and tests are isolated from each other.
var response = await client.GetAsync("http://localhost/Home/" + action);
var responseContent = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
public static TheoryData TagHelpersAreInheritedFromViewImportsPagesData
@ -129,16 +132,22 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(
"compiler/resources/TagHelpersWebSite.Employee.Create.html");
var outputFile = "compiler/resources/TagHelpersWebSite.Employee.Create.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
var response = await client.GetAsync("http://localhost/Employee/Create");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]
@ -147,8 +156,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(
"compiler/resources/TagHelpersWebSite.Employee.Details.AfterCreate.html");
var outputFile = "compiler/resources/TagHelpersWebSite.Employee.Details.AfterCreate.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
var validPostValues = new Dictionary<string, string>
{
{ "FullName", "Boo" },
@ -165,8 +175,13 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
[Fact]
@ -175,8 +190,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync(
"compiler/resources/TagHelpersWebSite.Employee.Create.Invalid.html");
var outputFile = "compiler/resources/TagHelpersWebSite.Employee.Create.Invalid.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
var validPostValues = new Dictionary<string, string>
{
{ "FullName", "Boo" },
@ -193,8 +209,13 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
}
}

View File

@ -15,6 +15,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public class ViewEngineTests
{
private const string SiteName = nameof(RazorWebSite);
private static readonly Assembly _assembly = typeof(ViewEngineTests).GetTypeInfo().Assembly;
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new Startup().ConfigureServices;
@ -318,7 +320,7 @@ View With Layout
public async Task ViewStartsCanUseDirectivesInjectedFromParentGlobals()
{
// Arrange
var expected =
var expected =
@"<view-start>Hello Controller-Person</view-start>
<page>Hello Controller-Person</page>";
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
@ -426,16 +428,21 @@ Partial that does not specify Layout
public async Task RazorView_SetsViewPathAndExecutingPagePath()
{
// Arrange
var expected = await GetType().GetTypeInfo().Assembly
.ReadResourceAsStringAsync("compiler/resources/ViewEngineController.ViewWithPaths.txt");
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var outputFile = "compiler/resources/ViewEngineController.ViewWithPaths.txt";
var expectedContent = await ResourceFile.ReadResourceAsync(_assembly, outputFile, sourceFile: false);
// Act
var body = await client.GetStringAsync("http://localhost/ViewWithPaths");
var responseContent = await client.GetStringAsync("http://localhost/ViewWithPaths");
// Assert
Assert.Equal(expected, body.Trim());
responseContent = responseContent.Trim();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent);
#endif
}
}
}

View File

@ -1,4 +1,4 @@
<!doctype html>
<!doctype html>
<html>
<head>
<title>Action Link with non unicode host</title>

View File

@ -1,4 +1,4 @@
<h2>Category: Laptops</h2>
<h2>Category: Laptops</h2>
<h2>Region: North</h2>
<h2>Cached content</h2>

View File

@ -1,4 +1,4 @@
<h2>Category: Phones</h2>
<h2>Category: Phones</h2>
<h2>Region: North</h2>
<h2>Cached content</h2>

View File

@ -1,4 +1,4 @@
<h2>Category: Phones</h2>
<h2>Category: Phones</h2>
<h2>Region: East</h2>
<h2>Cached content</h2>

View File

@ -1,6 +1,3 @@

<html>
<body>
<form action="/Customer/MvcTagHelper_Customer" method="post">

View File

@ -1,6 +1,3 @@

<html>
<body>
<form action="/MvcTagHelper_Home/CreateWarehouse" method="post"> <div>

View File

@ -1,6 +1,3 @@

<html>
<body>
<form action="/Customer/MvcTagHelper_Customer" method="post">

View File

@ -1,6 +1,3 @@

<html>
<body>
<form action="HtmlEncode[[/MvcTagHelper_Home/EditWarehouse]]" method="HtmlEncode[[post]]">
@ -44,4 +41,4 @@ HtmlEncode[[Address_1]]</textarea>;
<input type="submit" />
</form>
</body>
</html>
</html>

View File

@ -1,6 +1,3 @@

<html>
<body>
<form action="/MvcTagHelper_Home/EditWarehouse" method="post">
@ -44,4 +41,4 @@ Address_1</textarea>;
<input type="submit" />
</form>
</body>
</html>
</html>

View File

@ -1,6 +1,3 @@

<html>
<body>
<form action="/MvcTagHelper_Home/EmployeeList" method="post">

View File

@ -1,4 +1,3 @@

<html>
<head>
<meta charset="utf-8" />
@ -57,4 +56,4 @@
Product_2 description</textarea>
</div> <input type="submit" />
</form></body>
</html>
</html>

View File

@ -1,4 +1,4 @@
<div>
<div>
<span class="bold">TestCarDealer</span>
<em>SE</em>
<input data-val="true" data-val-required="The Id field is required." id="Dealer_Id" name="Dealer.Id" type="hidden" value="32" />

View File

@ -1,4 +1,4 @@
<div>
<div>
<span class="bold">TestCarDealer</span>
<em>SE</em>
<input data-val="true" data-val-required="The Id field is required." id="Dealer_Id" name="Dealer.Id" type="hidden" value="43" />

View File

@ -1,4 +1,4 @@
<div class="left">
<div class="left">
<ul>
<li>
Vin: 8chars

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />

View File

@ -1,4 +1,4 @@
<Layout>
<Layout>
/Views/ViewWithPaths/_Layout.cshtml
/Views/ViewWithPaths/Index.cshtml
</Layout>

View File

@ -3,6 +3,7 @@
"../Microsoft.AspNet.Mvc.Xml.Test/XmlAssert.cs"
],
"compilationOptions": {
"define": [ "__RemoveThisBitTo__GENERATE_BASELINES" ],
"warningsAsErrors": "true"
},
"dependencies": {

View File

@ -4,6 +4,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.AspNet.Mvc.Razor.Directives;
using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Razor;
@ -19,6 +22,8 @@ namespace Microsoft.AspNet.Mvc.Razor
{
public class MvcRazorHostTest
{
private static Assembly _assembly = typeof(MvcRazorHostTest).Assembly;
[Theory]
[InlineData("//")]
[InlineData("C:/")]
@ -159,6 +164,40 @@ namespace Microsoft.AspNet.Mvc.Razor
RunRuntimeTest(host, scenarioName);
}
[Fact]
public void BasicVisitor_GeneratesCorrectLineMappings()
{
// Arrange
var fileProvider = new TestFileProvider();
var host = new MvcRazorHost(new DefaultChunkTreeCache(fileProvider))
{
DesignTimeMode = true
};
host.NamespaceImports.Clear();
var expectedLineMappings = new[]
{
BuildLineMapping(
documentAbsoluteIndex: 13,
documentLineIndex: 0,
documentCharacterIndex: 13,
generatedAbsoluteIndex: 1269,
generatedLineIndex: 32,
generatedCharacterIndex: 13,
contentLength: 4),
BuildLineMapping(
documentAbsoluteIndex: 43,
documentLineIndex: 2,
documentCharacterIndex: 5,
generatedAbsoluteIndex: 1353,
generatedLineIndex: 37,
generatedCharacterIndex: 6,
contentLength: 21),
};
// Act and Assert
RunDesignTimeTest(host, "Basic", expectedLineMappings);
}
[Fact]
public void InjectVisitor_GeneratesCorrectLineMappings()
{
@ -246,19 +285,25 @@ namespace Microsoft.AspNet.Mvc.Razor
string testName)
{
var inputFile = "TestFiles/Input/" + testName + ".cshtml";
var expectedCode = ReadResource("TestFiles/Output/Runtime/" + testName + ".cs");
var outputFile = "TestFiles/Output/Runtime/" + testName + ".cs";
var expectedCode = ResourceFile.ReadResource(_assembly, outputFile, sourceFile: false);
// Act
GeneratorResults results;
using (var stream = GetResourceStream(inputFile))
using (var stream = ResourceFile.GetResourceStream(_assembly, inputFile, sourceFile: true))
{
results = host.GenerateCode(inputFile, stream);
}
// Assert
Assert.True(results.Success);
Assert.Equal(expectedCode, results.GeneratedCode);
Assert.Empty(results.ParserErrors);
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedCode, results.GeneratedCode);
#else
Assert.Equal(expectedCode, results.GeneratedCode);
#endif
}
private static void RunDesignTimeTest(MvcRazorHost host,
@ -266,39 +311,60 @@ namespace Microsoft.AspNet.Mvc.Razor
IEnumerable<LineMapping> expectedLineMappings)
{
var inputFile = "TestFiles/Input/" + testName + ".cshtml";
var expectedCode = ReadResource("TestFiles/Output/DesignTime/" + testName + ".cs");
var outputFile = "TestFiles/Output/DesignTime/" + testName + ".cs";
var expectedCode = ResourceFile.ReadResource(_assembly, outputFile, sourceFile: false);
// Act
GeneratorResults results;
using (var stream = GetResourceStream(inputFile))
using (var stream = ResourceFile.GetResourceStream(_assembly, inputFile, sourceFile: true))
{
results = host.GenerateCode(inputFile, stream);
}
// Assert
Assert.True(results.Success);
Assert.Equal(expectedCode, results.GeneratedCode);
Assert.Empty(results.ParserErrors);
Assert.Equal(expectedLineMappings, results.DesignTimeLineMappings);
}
private static string ReadResource(string resourceName)
{
using (var stream = GetResourceStream(resourceName))
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedCode, results.GeneratedCode);
Assert.NotNull(results.DesignTimeLineMappings); // Guard
if (expectedLineMappings == null ||
!Enumerable.SequenceEqual(expectedLineMappings, results.DesignTimeLineMappings))
{
using (var streamReader = new StreamReader(stream))
var lineMappings = new StringBuilder();
lineMappings.AppendLine($"// !!! Do not check in. Instead paste content into test method. !!!");
lineMappings.AppendLine();
var indent = " ";
lineMappings.AppendLine($"{ indent }var expectedLineMappings = new[]");
lineMappings.AppendLine($"{ indent }{{");
foreach (var lineMapping in results.DesignTimeLineMappings)
{
return streamReader.ReadToEnd();
var innerIndent = indent + " ";
var documentLocation = lineMapping.DocumentLocation;
var generatedLocation = lineMapping.GeneratedLocation;
lineMappings.AppendLine($"{ innerIndent }{ nameof(BuildLineMapping) }(");
innerIndent += " ";
lineMappings.AppendLine($"{ innerIndent }documentAbsoluteIndex: { documentLocation.AbsoluteIndex },");
lineMappings.AppendLine($"{ innerIndent }documentLineIndex: { documentLocation.LineIndex },");
lineMappings.AppendLine($"{ innerIndent }documentCharacterIndex: { documentLocation.CharacterIndex },");
lineMappings.AppendLine($"{ innerIndent }generatedAbsoluteIndex: { generatedLocation.AbsoluteIndex },");
lineMappings.AppendLine($"{ innerIndent }generatedLineIndex: { generatedLocation.LineIndex },");
lineMappings.AppendLine($"{ innerIndent }generatedCharacterIndex: { generatedLocation.CharacterIndex },");
lineMappings.AppendLine($"{ innerIndent }contentLength: { generatedLocation.ContentLength }),");
}
lineMappings.AppendLine($"{ indent }}};");
var lineMappingFile = Path.ChangeExtension(outputFile, "lineMappings.cs");
ResourceFile.UpdateFile(_assembly, lineMappingFile, previousContent: null, content: lineMappings.ToString());
}
}
private static Stream GetResourceStream(string resourceName)
{
resourceName = "Microsoft.AspNet.Mvc.Razor.Host.Test." + resourceName.Replace('/', '.');
var assembly = typeof(MvcRazorHostTest).Assembly;
return assembly.GetManifestResourceStream(resourceName);
#else
Assert.Equal(expectedCode, results.GeneratedCode);
Assert.Equal(expectedLineMappings, results.DesignTimeLineMappings);
#endif
}
private static LineMapping BuildLineMapping(int documentAbsoluteIndex,
@ -345,36 +411,43 @@ namespace Microsoft.AspNet.Mvc.Razor
{
public TestMvcRazorHost(IChunkTreeCache ChunkTreeCache)
: base(ChunkTreeCache)
{ }
{
}
public override CodeGenerator DecorateCodeGenerator(CodeGenerator incomingBuilder, CodeGeneratorContext context)
public override CodeGenerator DecorateCodeGenerator(
CodeGenerator incomingBuilder,
CodeGeneratorContext context)
{
base.DecorateCodeGenerator(incomingBuilder, context);
return new TestCSharpCodeGenerator(context,
DefaultModel,
"Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute",
new GeneratedTagHelperAttributeContext
{
ModelExpressionTypeName = ModelExpressionType,
CreateModelExpressionMethodName = CreateModelExpressionMethod
});
return new TestCSharpCodeGenerator(
context,
DefaultModel,
"Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute",
new GeneratedTagHelperAttributeContext
{
ModelExpressionTypeName = ModelExpressionType,
CreateModelExpressionMethodName = CreateModelExpressionMethod
});
}
protected class TestCSharpCodeGenerator : MvcCSharpCodeGenerator
{
private readonly GeneratedTagHelperAttributeContext _tagHelperAttributeContext;
public TestCSharpCodeGenerator(CodeGeneratorContext context,
string defaultModel,
string activateAttribute,
GeneratedTagHelperAttributeContext tagHelperAttributeContext)
public TestCSharpCodeGenerator(
CodeGeneratorContext context,
string defaultModel,
string activateAttribute,
GeneratedTagHelperAttributeContext tagHelperAttributeContext)
: base(context, defaultModel, activateAttribute, tagHelperAttributeContext)
{
_tagHelperAttributeContext = tagHelperAttributeContext;
}
protected override CSharpCodeVisitor CreateCSharpCodeVisitor(CSharpCodeWriter writer, CodeGeneratorContext context)
protected override CSharpCodeVisitor CreateCSharpCodeVisitor(
CSharpCodeWriter writer,
CodeGeneratorContext context)
{
var visitor = base.CreateCSharpCodeVisitor(writer, context);
visitor.TagHelperRenderer = new NoUniqueIdsTagHelperCodeRenderer(visitor, writer, context)
@ -387,11 +460,13 @@ namespace Microsoft.AspNet.Mvc.Razor
private class NoUniqueIdsTagHelperCodeRenderer : CSharpTagHelperCodeRenderer
{
public NoUniqueIdsTagHelperCodeRenderer(IChunkVisitor bodyVisitor,
CSharpCodeWriter writer,
CodeGeneratorContext context)
public NoUniqueIdsTagHelperCodeRenderer(
IChunkVisitor bodyVisitor,
CSharpCodeWriter writer,
CodeGeneratorContext context)
: base(bodyVisitor, writer, context)
{ }
{
}
protected override string GenerateUniqueId()
{

View File

@ -1,14 +1,15 @@
namespace Asp
namespace Asp
{
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using System.Threading.Tasks;
public class ASPV_TestFiles_Input_Basic_cshtml : Microsoft.AspNet.Mvc.Razor.RazorPage<dynamic>
{
private static object @__o;
private void @__RazorDesignTimeHelpers__()
{
#pragma warning disable 219
#pragma warning restore 219
}
#line hidden
public ASPV_TestFiles_Input_Basic_cshtml()
{
@ -28,33 +29,16 @@
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
PageExecutionContext.BeginContext(0, 4, true);
WriteLiteral("<div");
PageExecutionContext.EndContext();
WriteAttribute("class", Tuple.Create(" class=\"", 4), Tuple.Create("\"", 17),
Tuple.Create(Tuple.Create("", 12), Tuple.Create<System.Object, System.Int32>(
#line 1 "TestFiles/Input/Basic.cshtml"
logo
__o = logo;
#line default
#line hidden
, 12), false));
PageExecutionContext.BeginContext(18, 24, true);
WriteLiteral(">\r\n Hello world\r\n ");
PageExecutionContext.EndContext();
PageExecutionContext.BeginContext(43, 21, false);
Write(
#line 3 "TestFiles/Input/Basic.cshtml"
Html.Input("SomeKey")
__o = Html.Input("SomeKey");
#line default
#line hidden
);
PageExecutionContext.EndContext();
PageExecutionContext.BeginContext(64, 8, true);
WriteLiteral("\r\n</div>");
PageExecutionContext.EndContext();
}
#pragma warning restore 1998
}

View File

@ -1,4 +1,4 @@
namespace Asp
namespace Asp
{
#line 1 "TestFiles/Input/Inject.cshtml"
using MyNamespace

View File

@ -1,4 +1,4 @@
namespace Asp
namespace Asp
{
using System.Threading.Tasks;

View File

@ -1,4 +1,4 @@
namespace Asp
namespace Asp
{
using System.Threading.Tasks;

View File

@ -1,4 +1,4 @@
namespace Asp
namespace Asp
{
using System.Threading.Tasks;

View File

@ -1,4 +1,4 @@
namespace Asp
namespace Asp
{
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using System;

View File

@ -1,4 +1,4 @@
#pragma checksum "TestFiles/Input/Basic.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "63d2634be31f68aa89a0c1561d67c73cc446f3d4"
#pragma checksum "TestFiles/Input/Basic.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "63d2634be31f68aa89a0c1561d67c73cc446f3d4"
namespace Asp
{
using System;

View File

@ -1,4 +1,4 @@
#pragma checksum "TestFiles/Input/Inject.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "424b7fe9f12352c59210b5fa8c74ca8c9c67de81"
#pragma checksum "TestFiles/Input/Inject.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "424b7fe9f12352c59210b5fa8c74ca8c9c67de81"
namespace Asp
{
#line 1 "TestFiles/Input/Inject.cshtml"

View File

@ -1,4 +1,4 @@
#pragma checksum "TestFiles/Input/InjectWithModel.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "0c0e10d3fd8f5bf30eabc22ca0ee91355a13426d"
#pragma checksum "TestFiles/Input/InjectWithModel.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "0c0e10d3fd8f5bf30eabc22ca0ee91355a13426d"
namespace Asp
{
using System;

View File

@ -1,4 +1,4 @@
#pragma checksum "TestFiles/Input/InjectWithSemicolon.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "b753615982659a9805e6213ceced76ba06782038"
#pragma checksum "TestFiles/Input/InjectWithSemicolon.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "b753615982659a9805e6213ceced76ba06782038"
namespace Asp
{
using System;

View File

@ -1,4 +1,4 @@
#pragma checksum "TestFiles/Input/Model.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "2c1e88396568d309c236020e59bf2abacfadd612"
#pragma checksum "TestFiles/Input/Model.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "2c1e88396568d309c236020e59bf2abacfadd612"
namespace Asp
{
using System;

View File

@ -1,4 +1,4 @@
#pragma checksum "TestFiles/Input/ModelExpressionTagHelper.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "3b1d4af116a70f83c556ece1980f2e9364e6baa7"
#pragma checksum "TestFiles/Input/ModelExpressionTagHelper.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "3b1d4af116a70f83c556ece1980f2e9364e6baa7"
namespace Asp
{
using Microsoft.AspNet.Razor.Runtime.TagHelpers;

View File

@ -10,6 +10,9 @@
"commands": {
"test": "xunit.runner.aspnet"
},
"compilationOptions": {
"define": [ "__RemoveThisBitTo__GENERATE_BASELINES" ]
},
"frameworks": {
"dnx451": {
"dependencies": {

View File

@ -0,0 +1,245 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// Reader and, if GENERATE_BASELINES is defined, writer for files compiled into an assembly as resources.
/// </summary>
/// <remarks>Inspired by Razor's BaselineWriter and TestFile test classes.</remarks>
public static class ResourceFile
{
private static object writeLock = new object();
/// <summary>
/// Return <see cref="Stream"/> for <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest.
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> containing <paramref name="resourceName"/>.</param>
/// <param name="resourceName">
/// Name of the manifest resource in <paramref name="assembly"/>. A path relative to the test project
/// directory.
/// </param>
/// <param name="sourceFile">
/// If <c>true</c> <paramref name="resourceName"/> is used as a source file and must exist. Otherwise
/// <paramref name="resourceName"/> is an output file and, if <c>GENERATE_BASELINES</c> is defined, it will
/// soon be generated if missing.
/// </param>
/// <returns>
/// <see cref="Stream"/> for <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest. <c>null</c> if <c>GENERATE_BASELINES</c> is defined, <paramref name="sourceFile"/> is
/// <c>false</c>, and <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </returns>
/// <exception cref="Xunit.Sdk.TrueException">
/// Thrown if <c>GENERATE_BASELINES</c> is not defined or <paramref name="sourceFile"/> is <c>true</c> and
/// <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </exception>
public static Stream GetResourceStream(Assembly assembly, string resourceName, bool sourceFile)
{
// The DNX runtime compiles every file under the resources folder as a resource available at runtime with
// the same name as the file name.
var fullName = $"{ assembly.GetName().Name }.{ resourceName.Replace('/', '.') }";
if (!Exists(assembly, fullName))
{
#if GENERATE_BASELINES
if (sourceFile)
{
// Even when generating baselines, a missing source file is a serious problem.
Assert.True(false, $"Manifest resource: { fullName } not found.");
}
#else
// When not generating baselines, a missing source or output file is always an error.
Assert.True(false, $"Manifest resource '{ fullName }' not found.");
#endif
return null;
}
return assembly.GetManifestResourceStream(fullName);
}
/// <summary>
/// Return <see cref="string"/> content of <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest.
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> containing <paramref name="resourceName"/>.</param>
/// <param name="resourceName">
/// Name of the manifest resource in <paramref name="assembly"/>. A path relative to the test project
/// directory.
/// </param>
/// <param name="sourceFile">
/// If <c>true</c> <paramref name="resourceName"/> is used as a source file and must exist. Otherwise
/// <paramref name="resourceName"/> is an output file and, if <c>GENERATE_BASELINES</c> is defined, it will
/// soon be generated if missing.
/// </param>
/// <returns>
/// A <see cref="Task{string}"/> which on completion returns the <see cref="string"/> content of
/// <paramref name="resourceName"/> from <paramref name="assembly"/>'s manifest. <c>null</c> if
/// <c>GENERATE_BASELINES</c> is defined, <paramref name="sourceFile"/> is <c>false</c>, and
/// <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </returns>
/// <exception cref="Xunit.Sdk.TrueException">
/// Thrown if <c>GENERATE_BASELINES</c> is not defined or <paramref name="sourceFile"/> is <c>true</c> and
/// <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </exception>
/// <remarks>Normalizes line endings to <see cref="Environment.NewLine"/>.</remarks>
public static async Task<string> ReadResourceAsync(Assembly assembly, string resourceName, bool sourceFile)
{
using (var stream = GetResourceStream(assembly, resourceName, sourceFile))
{
if (stream == null)
{
return null;
}
using (var streamReader = new StreamReader(stream))
{
var content = await streamReader.ReadToEndAsync();
// Normalize line endings to Environment.NewLine. This removes core.autocrlf, core.eol,
// core.safecrlf, and .gitattributes from the equation and matches what MVC returns.
return content
.Replace("\r", string.Empty)
.Replace("\n", Environment.NewLine);
}
}
}
/// <summary>
/// Return <see cref="string"/> content of <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest.
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> containing <paramref name="resourceName"/>.</param>
/// <param name="resourceName">
/// Name of the manifest resource in <paramref name="assembly"/>. A path relative to the test project
/// directory.
/// </param>
/// <param name="sourceFile">
/// If <c>true</c> <paramref name="resourceName"/> is used as a source file and must exist. Otherwise
/// <paramref name="resourceName"/> is an output file and, if <c>GENERATE_BASELINES</c> is defined, it will
/// soon be generated if missing.
/// </param>
/// <returns>
/// The <see cref="string"/> content of <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest. <c>null</c> if <c>GENERATE_BASELINES</c> is defined, <paramref name="sourceFile"/> is
/// <c>false</c>, and <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </returns>
/// <exception cref="Xunit.Sdk.TrueException">
/// Thrown if <c>GENERATE_BASELINES</c> is not defined or <paramref name="sourceFile"/> is <c>true</c> and
/// <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </exception>
/// <remarks>Normalizes line endings to <see cref="Environment.NewLine"/>.</remarks>
public static string ReadResource(Assembly assembly, string resourceName, bool sourceFile)
{
using (var stream = GetResourceStream(assembly, resourceName, sourceFile))
{
if (stream == null)
{
return null;
}
using (var streamReader = new StreamReader(stream))
{
var content = streamReader.ReadToEnd();
// Normalize line endings to Environment.NewLine. This removes core.autocrlf, core.eol,
// core.safecrlf, and .gitattributes from the equation and matches what MVC returns.
return content
.Replace("\r", string.Empty)
.Replace("\n", Environment.NewLine);
}
}
}
/// <summary>
/// Write <paramref name="content"/> to file that will become <paramref name="resourceName"/> in
/// <paramref name="assembly"/> the next time the project is built. Does nothing if
/// <paramref name="previousContent"/> and <paramref name="content"/> already match.
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> containing <paramref name="resourceName"/>.</param>
/// <param name="resourceName">
/// Name of the manifest resource in <paramref name="assembly"/>. A path relative to the test project
/// directory.
/// </param>
/// <param name="previousContent">
/// Current content of <paramref name="resourceName"/>. <c>null</c> if <paramref name="resourceName"/> does
/// not currently exist in <paramref name="assembly"/>.
/// </param>
/// <param name="content">
/// New content of <paramref name="resourceName"/> in <paramref name="assembly"/>.
/// </param>
[Conditional("GENERATE_BASELINES")]
public static void UpdateFile(Assembly assembly, string resourceName, string previousContent, string content)
{
if (!string.Equals(previousContent, content, StringComparison.Ordinal))
{
// The DNX runtime compiles every file under the resources folder as a resource available at runtime with
// the same name as the file name. Need to update this file on disc.
var projectName = assembly.GetName().Name;
var projectPath = GetProjectPath(projectName);
var fullPath = Path.Combine(projectPath, resourceName);
WriteFile(fullPath, content);
}
}
private static bool Exists(Assembly assembly, string fullName)
{
var resourceNames = assembly.GetManifestResourceNames();
foreach (var resourceName in resourceNames)
{
// Resource names are case-sensitive.
if (string.Equals(fullName, resourceName, StringComparison.Ordinal))
{
return true;
}
}
return false;
}
private static string GetProjectPath(string projectName)
{
// Initial guess: Already in the project directory.
var projectPath = Path.GetFullPath(".");
var currentDirectoryName = new DirectoryInfo(projectPath).Name;
if (!string.Equals(projectName, currentDirectoryName, StringComparison.Ordinal))
{
// Not running from test project directory. Should be in "test" or solution directory.
if (string.Equals("test", currentDirectoryName, StringComparison.Ordinal))
{
projectPath = Path.Combine(projectPath, projectName);
}
else
{
projectPath = Path.Combine(projectPath, "test", projectName);
}
}
return projectPath;
}
private static void WriteFile(string fullPath, string content)
{
// Serialize writes to minimize contention for file handles and directory access.
lock (writeLock)
{
// Write content to the file, creating it if necessary.
using (var stream = File.Open(fullPath, FileMode.Create, FileAccess.Write))
{
using (var writer = new StreamWriter(stream))
{
writer.Write(content);
}
}
}
}
}
}