From 2d5a1737a2aaebda1de080e001dd8382ff348046 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 20 Jun 2018 15:14:11 -0700 Subject: [PATCH 1/8] Update Razor SDK packing logic to not include Pack at properties layer. - Added test to verify that no-build scenarios work as expected. #2378 --- .../Sdk.Razor.CurrentVersion.props | 5 +-- .../Sdk.Razor.CurrentVersion.targets | 12 ++++++ .../IntegrationTests/PackIntegrationTest.cs | 40 +++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Sdk.Razor.CurrentVersion.props b/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Sdk.Razor.CurrentVersion.props index 015a7953e8..2ac65f5424 100644 --- a/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Sdk.Razor.CurrentVersion.props +++ b/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Sdk.Razor.CurrentVersion.props @@ -67,10 +67,7 @@ Copyright (c) .NET Foundation. All rights reserved. - - $(IncludeRazorContentInPack) - - + diff --git a/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets b/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets index 2e2dba43b1..d100b112cc 100644 --- a/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets +++ b/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets @@ -74,6 +74,11 @@ Copyright (c) .NET Foundation. All rights reserved. ResolveRazorGenerateInputs + + ResolveRazorGenerateInputs; + $(GenerateNuspecDependsOn) + + _RazorPrepareForRun; $(PrepareForRunDependsOn) @@ -326,6 +331,13 @@ Copyright (c) .NET Foundation. All rights reserved. + + + + + diff --git a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/PackIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/PackIntegrationTest.cs index 317116111c..80bba18f13 100644 --- a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/PackIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/PackIntegrationTest.cs @@ -15,6 +15,46 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests { } + [Fact] + [InitializeTestProject("ClassLibrary")] + public async Task Pack__NoBuild_Works_IncludesRazorAssembly() + { + var result = await DotnetMSBuild("Build"); + Assert.BuildPassed(result); + + result = await DotnetMSBuild("Pack", "/p:NoBuild=true"); + Assert.BuildPassed(result); + + Assert.FileExists(result, OutputPath, "ClassLibrary.dll"); + Assert.FileExists(result, OutputPath, "ClassLibrary.Views.dll"); + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + // Travis on OSX produces different full paths in C# and MSBuild + Assert.NuspecContains( + result, + Path.Combine("obj", Configuration, "ClassLibrary.1.0.0.nuspec"), + $""); + + Assert.NuspecDoesNotContain( + result, + Path.Combine("obj", Configuration, "ClassLibrary.1.0.0.nuspec"), + $""); + } + + Assert.NuspecDoesNotContain( + result, + Path.Combine("obj", Configuration, "ClassLibrary.1.0.0.nuspec"), + @""); + + Assert.NupkgContains( + result, + Path.Combine("bin", Configuration, "ClassLibrary.1.0.0.nupkg"), + Path.Combine("lib", "netstandard2.0", "ClassLibrary.Views.dll")); + } + [Fact] [InitializeTestProject("ClassLibrary")] public async Task Pack_Works_IncludesRazorAssembly() From e23c2652b7e123f35935a23e60ee60480caae9e7 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 21 Jun 2018 12:46:43 -0700 Subject: [PATCH 2/8] Add NoBuild test that includes content. - Also fixed wording of existing nobuild test. --- .../IntegrationTests/PackIntegrationTest.cs | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/PackIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/PackIntegrationTest.cs index 80bba18f13..e0d7b86678 100644 --- a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/PackIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/PackIntegrationTest.cs @@ -17,7 +17,28 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests [Fact] [InitializeTestProject("ClassLibrary")] - public async Task Pack__NoBuild_Works_IncludesRazorAssembly() + public async Task Pack_NoBuild_IncludeRazorContent_IncludesRazorViewContent() + { + var result = await DotnetMSBuild("Build"); + Assert.BuildPassed(result); + + result = await DotnetMSBuild("Pack", "/p:NoBuild=true /p:IncludeRazorContentInPack=true"); + Assert.BuildPassed(result); + + Assert.NuspecContains( + result, + Path.Combine("obj", Configuration, "ClassLibrary.1.0.0.nuspec"), + @""); + + Assert.NupkgContains( + result, + Path.Combine("bin", Configuration, "ClassLibrary.1.0.0.nupkg"), + Path.Combine("contentFiles", "any", "netstandard2.0", "Views", "Shared", "_Layout.cshtml")); + } + + [Fact] + [InitializeTestProject("ClassLibrary")] + public async Task Pack_NoBuild_Works_IncludesRazorAssembly() { var result = await DotnetMSBuild("Build"); Assert.BuildPassed(result); From 1c9208ba110a16eb98085406fd7db874657b642c Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 28 Jun 2018 10:51:19 -0700 Subject: [PATCH 3/8] Update korebuild.json to restrict which VS is used. --- korebuild.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/korebuild.json b/korebuild.json index f0fcb05ac3..62a0761251 100644 --- a/korebuild.json +++ b/korebuild.json @@ -5,7 +5,7 @@ "visualstudio": { "required": false, "includePrerelease": true, - "minVersion": "15.0.26730.03", + "versionRange": "[15.0.26730.03, 15.8)", "requiredWorkloads": [ "Microsoft.VisualStudio.Component.VSSDK" ] From e7db3f840b119e2fe08550d1e568b51dd0256eda Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Sat, 16 Jun 2018 01:05:59 +0530 Subject: [PATCH 4/8] Handle pipe name with whitespace properly --- .../Program.cs | 24 +++++++++++++-- .../ServerProtocol/ServerConnection.cs | 15 +++++++--- .../ServerProtocol/ServerLogger.cs | 2 +- .../BuildServerIntegrationTest.cs | 29 +++++++++++++++++++ .../BuildServerTestFixture.cs | 21 ++++---------- .../MSBuildIntegrationTestBase.cs | 2 +- 6 files changed, 69 insertions(+), 24 deletions(-) diff --git a/src/Microsoft.AspNetCore.Razor.Tools/Program.cs b/src/Microsoft.AspNetCore.Razor.Tools/Program.cs index 27807cd23e..8d9c5518c5 100644 --- a/src/Microsoft.AspNetCore.Razor.Tools/Program.cs +++ b/src/Microsoft.AspNetCore.Razor.Tools/Program.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.IO; using System.Threading; using Microsoft.CodeAnalysis; @@ -16,17 +17,34 @@ namespace Microsoft.AspNetCore.Razor.Tools var cancel = new CancellationTokenSource(); Console.CancelKeyPress += (sender, e) => { cancel.Cancel(); }; + var outputWriter = new StringWriter(); + var errorWriter = new StringWriter(); + // Prevent shadow copying. var loader = new DefaultExtensionAssemblyLoader(baseDirectory: null); - var checker = new DefaultExtensionDependencyChecker(loader, Console.Out, Console.Error); + var checker = new DefaultExtensionDependencyChecker(loader, outputWriter, errorWriter); var application = new Application( cancel.Token, loader, checker, - (path, properties) => MetadataReference.CreateFromFile(path, properties)); + (path, properties) => MetadataReference.CreateFromFile(path, properties), + outputWriter, + errorWriter); - return application.Execute(args); + var result = application.Execute(args); + + var output = outputWriter.ToString(); + var error = errorWriter.ToString(); + + outputWriter.Dispose(); + errorWriter.Dispose(); + + // This will no-op if server logging is not enabled. + ServerLogger.Log(output); + ServerLogger.Log(error); + + return result; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Razor.Tools/ServerProtocol/ServerConnection.cs b/src/Microsoft.AspNetCore.Razor.Tools/ServerProtocol/ServerConnection.cs index 2583d1e0dc..d9fb8d4b11 100644 --- a/src/Microsoft.AspNetCore.Razor.Tools/ServerProtocol/ServerConnection.cs +++ b/src/Microsoft.AspNetCore.Razor.Tools/ServerProtocol/ServerConnection.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.CommandLineUtils; namespace Microsoft.AspNetCore.Razor.Tools { @@ -283,14 +284,20 @@ namespace Microsoft.AspNetCore.Razor.Tools // Internal for testing. internal static bool TryCreateServerCore(string clientDir, string pipeName, out int? processId, bool debug = false) { - string expectedPath; - string processArguments; processId = null; // The server should be in the same directory as the client var expectedCompilerPath = Path.Combine(clientDir, ServerName); - expectedPath = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH") ?? "dotnet"; - processArguments = $@"""{expectedCompilerPath}"" {(debug ? "--debug" : "")} server -p {pipeName}"; + var expectedPath = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH") ?? "dotnet"; + var argumentList = new string[] + { + expectedCompilerPath, + debug ? "--debug" : "", + "server", + "-p", + pipeName + }; + var processArguments = ArgumentEscaper.EscapeAndConcatenate(argumentList); if (!File.Exists(expectedCompilerPath)) { diff --git a/src/Microsoft.AspNetCore.Razor.Tools/ServerProtocol/ServerLogger.cs b/src/Microsoft.AspNetCore.Razor.Tools/ServerProtocol/ServerLogger.cs index be2e934160..2e38fc60c6 100644 --- a/src/Microsoft.AspNetCore.Razor.Tools/ServerProtocol/ServerLogger.cs +++ b/src/Microsoft.AspNetCore.Razor.Tools/ServerProtocol/ServerLogger.cs @@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Razor.Tools // Otherwise, assume that the environment variable specifies the name of the log file. if (Directory.Exists(loggingFileName)) { - loggingFileName = Path.Combine(loggingFileName, $"server.{loggingFileName}.{GetCurrentProcessId()}.log"); + loggingFileName = Path.Combine(loggingFileName, $"razorserver.{GetCurrentProcessId()}.log"); } // Open allowing sharing. We allow multiple processes to log to the same file, so we use share mode to allow that. diff --git a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildServerIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildServerIntegrationTest.cs index 60076a7a67..e570b9ee93 100644 --- a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildServerIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildServerIntegrationTest.cs @@ -164,5 +164,34 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests Assert.Equal(0, exitCode); Assert.Contains("shut down completed", output.ToString()); } + + [Fact] + [InitializeTestProject("SimpleMvc")] + public async Task Build_WithWhiteSpaceInPipeName_BuildsSuccessfully() + { + // Start the server + var pipeName = "pipe with whitespace"; + var fixture = new BuildServerTestFixture(pipeName); + + try + { + // Run a build + var result = await DotnetMSBuild( + "Build", + "/p:_RazorForceBuildServer=true", + buildServerPipeName: pipeName); + + Assert.BuildPassed(result); + Assert.FileExists(result, OutputPath, "SimpleMvc.dll"); + Assert.FileExists(result, OutputPath, "SimpleMvc.pdb"); + Assert.FileExists(result, OutputPath, "SimpleMvc.Views.dll"); + Assert.FileExists(result, OutputPath, "SimpleMvc.Views.pdb"); + } + finally + { + // Shutdown the server + fixture.Dispose(); + } + } } } diff --git a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildServerTestFixture.cs b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildServerTestFixture.cs index ea18e6cfa0..5c1a17e5c7 100644 --- a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildServerTestFixture.cs +++ b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildServerTestFixture.cs @@ -14,9 +14,13 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests { private static readonly TimeSpan _defaultShutdownTimeout = TimeSpan.FromSeconds(60); - public BuildServerTestFixture() + public BuildServerTestFixture() : this(Guid.NewGuid().ToString()) { - PipeName = Guid.NewGuid().ToString(); + } + + internal BuildServerTestFixture(string pipeName) + { + PipeName = pipeName; if (!ServerConnection.TryCreateServerCore(Environment.CurrentDirectory, PipeName, out var processId)) { @@ -54,18 +58,5 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests } } } - - private static string RecursiveFind(string path, string start) - { - var test = Path.Combine(start, path); - if (File.Exists(test)) - { - return start; - } - else - { - return RecursiveFind(path, new DirectoryInfo(start).Parent.FullName); - } - } } } diff --git a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/MSBuildIntegrationTestBase.cs b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/MSBuildIntegrationTestBase.cs index c9765901cd..4cde21a898 100644 --- a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/MSBuildIntegrationTestBase.cs +++ b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/MSBuildIntegrationTestBase.cs @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests if (!suppressBuildServer) { - buildArgumentList.Add($"/p:_RazorBuildServerPipeName={buildServerPipeName ?? BuildServer.PipeName}"); + buildArgumentList.Add($@"/p:_RazorBuildServerPipeName=""{buildServerPipeName ?? BuildServer.PipeName}"""); // The build server will not be used in netcoreapp2.0 because PipeOptions.CurrentUserOnly is not available. // But we still want to make sure to run the tests on the server. So suppress that check. From bbddd29ab87a75f61b42226854ad5dc98c74192d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 8 Jul 2018 12:25:33 -0700 Subject: [PATCH 5/8] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 22 +++++++++++----------- korebuild-lock.txt | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c83a59e6f3..52cf55ba86 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,22 +4,22 @@ 0.10.13 - 2.2.0-preview1-17090 - 2.2.0-preview1-34530 - 2.2.0-preview1-34530 - 2.2.0-preview1-34530 + 2.2.0-preview1-17099 + 2.2.0-preview1-34640 + 2.2.0-preview1-34640 + 2.2.0-preview1-34640 15.6.82 15.6.82 15.6.82 2.8.0 2.8.0 - 2.2.0-preview1-34530 - 2.2.0-preview1-34530 + 2.2.0-preview1-34640 + 2.2.0-preview1-34640 2.2.0-preview1-26618-02 - 2.2.0-preview1-34530 - 2.2.0-preview1-34530 - 2.0.0 - 2.1.0 + 2.2.0-preview1-34640 + 2.2.0-preview1-34640 + 2.0.7 + 2.1.1 2.2.0-preview1-26618-02 15.6.1 15.0.26606 @@ -59,7 +59,7 @@ 2.9.0-beta4-62911-02 0.8.0 2.3.1 - 2.4.0-beta.1.build3945 + 2.4.0-rc.1.build4038 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3e694b2ed8..8b9d17825f 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17090 -commithash:b19e903e946579cd9482089bce7d917e8bacd765 +version:2.2.0-preview1-17099 +commithash:263ed1db9866b6b419b1f5d5189a712aa218acb3 From 74667eda9c5a1826b2876a718e6de22832ef6550 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 19 Jun 2018 11:01:39 -0700 Subject: [PATCH 6/8] Don't specify MainEntryPoint when compiling Razor assembly --- .../Microsoft.NET.Sdk.Razor.Compilation.targets | 2 +- .../IntegrationTests/BuildIntegrationTest.cs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Compilation.targets b/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Compilation.targets index c8ec7205db..102315ebc4 100644 --- a/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Compilation.targets +++ b/src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Compilation.targets @@ -42,6 +42,7 @@ Copyright (c) .NET Foundation. All rights reserved. Remove @(DocFileItem) Remove PdbFile="$(PdbFile)" Remove OutputRefAssembly="@(IntermediateRefAssembly)" + Remove MainEntryPoint="$(StartupObject)" Remove EmbedAllSources="$(EmbedAllSources)" - not supported by our supported version of MSBuild @@ -133,7 +134,6 @@ Copyright (c) .NET Foundation. All rights reserved. KeyFile="$(KeyOriginatorFile)" LangVersion="$(LangVersion)" LinkResources="@(LinkResource)" - MainEntryPoint="$(StartupObject)" ModuleAssemblyName="$(ModuleAssemblyName)" NoConfig="true" NoLogo="$(NoLogo)" diff --git a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildIntegrationTest.cs index 541cac3523..030f55dd7b 100644 --- a/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildIntegrationTest.cs @@ -553,6 +553,21 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests Assert.BuildPassed(result); } + [Fact] + [InitializeTestProject("SimpleMvc")] + public async Task Build_WithStartupObjectSpecified_Works() + { + var result = await DotnetMSBuild("Build", $"/p:StartupObject=SimpleMvc.Program"); + + Assert.BuildPassed(result); + + Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.Views.dll"); + Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.Views.pdb"); + + Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.Views.dll"); + Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.Views.pdb"); + } + private static DependencyContext ReadDependencyContext(string depsFilePath) { var reader = new DependencyContextJsonReader(); From cfd63e1e2e8cf45ce0175de121f000a58daf3036 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 13 Jul 2018 12:36:18 -0700 Subject: [PATCH 7/8] Change HTML splitting logic to not split on surrogate pairs. - When a surrogate pair is about to be split down the middle we reduce the size of our split by 1 character. This way we split right before a surrogate pair. In the case of zero width joiners, if we split on a zero width joiner we still render valid bytes because the zero width joiner by itself can stand alone. - Added tests for the various split cases. #2470 --- .../CodeGeneration/RuntimeNodeWriter.cs | 58 +++++++++---- .../CodeGeneration/RuntimeNodeWriterTest.cs | 85 +++++++++++++++++++ 2 files changed, 128 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeNodeWriter.cs b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeNodeWriter.cs index 9f08216548..f913a53fc4 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeNodeWriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeNodeWriter.cs @@ -325,28 +325,56 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var content = builder.ToString(); - var charactersConsumed = 0; + WriteHtmlLiteral(context, MaxStringLiteralLength, content); + } - // Render the string in pieces to avoid Roslyn OOM exceptions at compile time: https://github.com/aspnet/External/issues/54 - while (charactersConsumed < content.Length) + // Internal for testing + internal void WriteHtmlLiteral(CodeRenderingContext context, int maxStringLiteralLength, string literal) + { + if (literal.Length <= maxStringLiteralLength) { - string textToRender; - if (content.Length <= MaxStringLiteralLength) + WriteLiteral(literal); + return; + } + + // String is too large, render the string in pieces to avoid Roslyn OOM exceptions at compile time: https://github.com/aspnet/External/issues/54 + var charactersConsumed = 0; + do + { + var charactersRemaining = literal.Length - charactersConsumed; + var charactersToSubstring = Math.Min(maxStringLiteralLength, charactersRemaining); + var lastCharBeforeSplitIndex = charactersConsumed + charactersToSubstring - 1; + var lastCharBeforeSplit = literal[lastCharBeforeSplitIndex]; + + if (char.IsHighSurrogate(lastCharBeforeSplit)) { - textToRender = content; - } - else - { - var charactersToSubstring = Math.Min(MaxStringLiteralLength, content.Length - charactersConsumed); - textToRender = content.Substring(charactersConsumed, charactersToSubstring); + if (charactersRemaining > 1) + { + // Take one less character this iteration. We're attempting to split inbetween a surrogate pair. + // This can happen when something like an emoji sits on the barrier between splits; if we were to + // split the emoji we'd end up with invalid bytes in our output. + charactersToSubstring--; + } + else + { + // The user has an invalid file with a partial surrogate a the splitting point. + // We'll let the invalid character flow but we'll explode later on. + } } - context.CodeWriter - .WriteStartMethodInvocation(WriteHtmlContentMethod) - .WriteStringLiteral(textToRender) - .WriteEndMethodInvocation(); + var textToRender = literal.Substring(charactersConsumed, charactersToSubstring); + + WriteLiteral(textToRender); charactersConsumed += textToRender.Length; + } while (charactersConsumed < literal.Length); + + void WriteLiteral(string content) + { + context.CodeWriter + .WriteStartMethodInvocation(WriteHtmlContentMethod) + .WriteStringLiteral(content) + .WriteEndMethodInvocation(); } } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeNodeWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeNodeWriterTest.cs index 443acf376f..b2d99dbd4c 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeNodeWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeNodeWriterTest.cs @@ -339,6 +339,91 @@ if (true) { } ignoreLineEndingDifferences: true); } + [Fact] + public void WriteHtmlLiteral_WithinMaxSize_WritesSingleLiteral() + { + // Arrange + var codeWriter = new CodeWriter(); + var writer = new RuntimeNodeWriter(); + var context = TestCodeRenderingContext.CreateRuntime(); + + // Act + writer.WriteHtmlLiteral(context, maxStringLiteralLength: 6, "Hello"); + + // Assert + var csharp = context.CodeWriter.GenerateCode(); + Assert.Equal( +@"WriteLiteral(""Hello""); +", + csharp, + ignoreLineEndingDifferences: true); + } + + [Fact] + public void WriteHtmlLiteral_GreaterThanMaxSize_WritesMultipleLiterals() + { + // Arrange + var codeWriter = new CodeWriter(); + var writer = new RuntimeNodeWriter(); + var context = TestCodeRenderingContext.CreateRuntime(); + + // Act + writer.WriteHtmlLiteral(context, maxStringLiteralLength: 6, "Hello World"); + + // Assert + var csharp = context.CodeWriter.GenerateCode(); + Assert.Equal( +@"WriteLiteral(""Hello ""); +WriteLiteral(""World""); +", + csharp, + ignoreLineEndingDifferences: true); + } + + [Fact] + public void WriteHtmlLiteral_GreaterThanMaxSize_SingleEmojisSplit() + { + // Arrange + var codeWriter = new CodeWriter(); + var writer = new RuntimeNodeWriter(); + var context = TestCodeRenderingContext.CreateRuntime(); + + // Act + writer.WriteHtmlLiteral(context, maxStringLiteralLength: 2, " ๐Ÿ‘ฆ"); + + // Assert + var csharp = context.CodeWriter.GenerateCode(); + Assert.Equal( +@"WriteLiteral("" ""); +WriteLiteral(""๐Ÿ‘ฆ""); +", + csharp, + ignoreLineEndingDifferences: true); + } + + [Fact] + public void WriteHtmlLiteral_GreaterThanMaxSize_SequencedZeroWithJoinedEmojisSplit() + { + // Arrange + var codeWriter = new CodeWriter(); + var writer = new RuntimeNodeWriter(); + var context = TestCodeRenderingContext.CreateRuntime(); + + // Act + writer.WriteHtmlLiteral(context, maxStringLiteralLength: 6, "๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง"); + + // Assert + var csharp = context.CodeWriter.GenerateCode(); + Assert.Equal( +@"WriteLiteral(""๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€""); +WriteLiteral(""๐Ÿ‘งโ€๐Ÿ‘ง""); +WriteLiteral(""๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€""); +WriteLiteral(""๐Ÿ‘งโ€๐Ÿ‘ง""); +", + csharp, + ignoreLineEndingDifferences: true); + } + [Fact] public void WriteHtmlContent_RendersContentCorrectly() { From cb9216986035bfad280e4688d29ca18d68d19b34 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 15 Jul 2018 12:24:46 -0700 Subject: [PATCH 8/8] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 52cf55ba86..7251e35811 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,21 +5,21 @@ 0.10.13 2.2.0-preview1-17099 - 2.2.0-preview1-34640 - 2.2.0-preview1-34640 - 2.2.0-preview1-34640 + 2.2.0-preview1-34694 + 2.2.0-preview1-34694 + 2.2.0-preview1-34694 15.6.82 15.6.82 15.6.82 2.8.0 2.8.0 - 2.2.0-preview1-34640 - 2.2.0-preview1-34640 - 2.2.0-preview1-26618-02 - 2.2.0-preview1-34640 - 2.2.0-preview1-34640 - 2.0.7 - 2.1.1 + 2.2.0-preview1-34694 + 2.2.0-preview1-34694 + 2.1.0 + 2.2.0-preview1-34694 + 2.2.0-preview1-34694 + 2.0.9 + 2.1.2 2.2.0-preview1-26618-02 15.6.1 15.0.26606 @@ -43,9 +43,9 @@ 2.0.3 11.0.2 1.1.92 - 4.6.0-preview1-26617-01 + 4.5.0 4.3.0 - 4.6.0-preview1-26617-01 + 4.5.0 9.0.1 2.9.0-beta4-62911-02 2.9.0-beta4-62911-02 @@ -57,7 +57,7 @@ 2.9.0-beta4-62911-02 2.9.0-beta4-62911-02 2.9.0-beta4-62911-02 - 0.8.0 + 0.9.0 2.3.1 2.4.0-rc.1.build4038