Verify support for reporting errors using MSBuild (#1867)
* Verify support for reporting errors using MSBuild * Verifies that CSC errors get mapped to the right place Resolves #1850
This commit is contained in:
parent
d419566534
commit
3f948ad3c5
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
|
|
@ -60,7 +59,7 @@ namespace Microsoft.AspNetCore.Razor.GenerateTool
|
|||
success = false;
|
||||
foreach (var error in result.CSharpDocument.Diagnostics)
|
||||
{
|
||||
Console.Error.WriteLine(error.GetMessage());
|
||||
Console.Error.WriteLine(error.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,17 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||
{
|
||||
internal class Assert : Xunit.Assert
|
||||
{
|
||||
// Matches `{filename}: error {code}: {message} [{project}]
|
||||
// See https://stackoverflow.com/questions/3441452/msbuild-and-ignorestandarderrorwarningformat/5180353#5180353
|
||||
private static readonly Regex ErrorRegex = new Regex(@"^(?'location'.+): error (?'errorcode'[A-Z0-9]+): (?'message'.+) \[(?'project'.+)\]$");
|
||||
|
||||
public static void BuildPassed(MSBuildResult result)
|
||||
{
|
||||
if (result == null)
|
||||
|
|
@ -24,6 +27,52 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
}
|
||||
}
|
||||
|
||||
public static void BuildError(MSBuildResult result, string errorCode, string location = null)
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(result));
|
||||
}
|
||||
|
||||
// We don't really need to search line by line, I'm doing this so that it's possible/easy to debug.
|
||||
var lines = result.Output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (var i = 0; i < lines.Length; i++)
|
||||
{
|
||||
var line = lines[i];
|
||||
var match = ErrorRegex.Match(line);
|
||||
if (match.Success)
|
||||
{
|
||||
if (match.Groups["errorcode"].Value != errorCode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (location != null && match.Groups["location"].Value != location)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is a match
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new BuildErrorMissingException(result, errorCode);
|
||||
}
|
||||
|
||||
public static void BuildFailed(MSBuildResult result)
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(result));
|
||||
};
|
||||
|
||||
if (result.ExitCode == 0)
|
||||
{
|
||||
throw new BuildPassedException(result);
|
||||
}
|
||||
}
|
||||
|
||||
public static void FileExists(MSBuildResult result, params string[] paths)
|
||||
{
|
||||
if (result == null)
|
||||
|
|
@ -106,6 +155,20 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
}
|
||||
}
|
||||
|
||||
private class BuildErrorMissingException : MSBuildXunitException
|
||||
{
|
||||
public BuildErrorMissingException(MSBuildResult result, string errorCode)
|
||||
: base(result)
|
||||
{
|
||||
ErrorCode = errorCode;
|
||||
}
|
||||
|
||||
public string ErrorCode { get; }
|
||||
|
||||
protected override string Heading => $"Error code '{ErrorCode}' was not found.";
|
||||
}
|
||||
|
||||
|
||||
private class BuildFailedException : MSBuildXunitException
|
||||
{
|
||||
public BuildFailedException(MSBuildResult result)
|
||||
|
|
@ -113,7 +176,17 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
{
|
||||
}
|
||||
|
||||
protected override string Heading => "Build failed:";
|
||||
protected override string Heading => "Build failed.";
|
||||
}
|
||||
|
||||
private class BuildPassedException : MSBuildXunitException
|
||||
{
|
||||
public BuildPassedException(MSBuildResult result)
|
||||
: base(result)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string Heading => "Build should have failed, but it passed.";
|
||||
}
|
||||
|
||||
private class FileMissingException : MSBuildXunitException
|
||||
|
|
|
|||
|
|
@ -19,5 +19,24 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
Assert.FileExists(result, OutputPath, "SimpleMvc.dll");
|
||||
Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.dll");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[InitializeTestProject("SimpleMvc")]
|
||||
public async Task Build_ErrorInGeneratedCode_ReportsMSBuildError()
|
||||
{
|
||||
// Introducing a C# semantic error
|
||||
ReplaceContent("@{ var foo = \"\".Substring(\"bleh\"); }", "Views", "Home", "Index.cshtml");
|
||||
|
||||
var result = await DotnetMSBuild("Build", "/p:RazorCompileOnBuild=true");
|
||||
|
||||
Assert.BuildFailed(result);
|
||||
|
||||
// Verifying that the error correctly gets mapped to the original source
|
||||
Assert.BuildError(result, "CS1503", location: Path.Combine("Views", "Home", "Index.cshtml") + "(1,27)");
|
||||
|
||||
// Compilation failed without creating the views assembly
|
||||
Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.dll");
|
||||
Assert.FileDoesNotExist(result, IntermediateOutputPath, "SimpleMvc.PrecompiledViews.dll");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -46,5 +47,26 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
|
||||
return MSBuildProcessManager.RunProcessAsync(Project, $"{restoreArgument} /t:{target} /p:Configuration={Configuration} {args}", timeout);
|
||||
}
|
||||
|
||||
internal void ReplaceContent(string content, params string[] paths)
|
||||
{
|
||||
if (content == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(content));
|
||||
}
|
||||
|
||||
if (paths == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(paths));
|
||||
}
|
||||
|
||||
var filePath = Path.Combine(Project.DirectoryPath, Path.Combine(paths));
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
throw new InvalidOperationException($"File {filePath} could not be found.");
|
||||
}
|
||||
|
||||
File.WriteAllText(filePath, content, Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// 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.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -32,5 +30,27 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
Assert.FileExists(result, RazorIntermediateOutputPath, "Views", "Shared", "Error.cs");
|
||||
Assert.FileCountEquals(result, 8, RazorIntermediateOutputPath, "*.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[InitializeTestProject("SimpleMvc")]
|
||||
public async Task RazorGenerate_ErrorInRazorFile_ReportsMSBuildError()
|
||||
{
|
||||
// Introducing a syntax error, an unclosed brace
|
||||
ReplaceContent("@{", "Views", "Home", "Index.cshtml");
|
||||
|
||||
var result = await DotnetMSBuild("RazorGenerate");
|
||||
|
||||
Assert.BuildFailed(result);
|
||||
|
||||
// Looks like C:\...\Views\Home\Index.cshtml(1,2): error RZ1006: The code block is missi... [C:\Users\rynowak\AppData\Local\Temp\rwnv03ll.wb0\SimpleMvc.csproj]
|
||||
Assert.BuildError(result, "RZ1006");
|
||||
|
||||
// RazorGenerate should compile the assembly, but not the views.
|
||||
Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.dll");
|
||||
Assert.FileDoesNotExist(result, IntermediateOutputPath, "SimpleMvc.PrecompiledViews.dll");
|
||||
|
||||
// The file should still be generated even if we had a Razor syntax error.
|
||||
Assert.FileExists(result, RazorIntermediateOutputPath, "Views", "Home", "Index.cs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue