protected void AssertCSharpDocumentMatchesBaseline(RazorCodeDocument codeDocument)
        {
            var document = codeDocument.GetCSharpDocument();

            // Normalize newlines to match those in the baseline.
            var actualCode = document.GeneratedCode.Replace("\r", "").Replace("\n", "\r\n");

            var baselineFilePath            = GetBaselineFilePath(codeDocument, ".codegen.cs");
            var baselineDiagnosticsFilePath = GetBaselineFilePath(codeDocument, ".diagnostics.txt");
            var baselineMappingsFilePath    = GetBaselineFilePath(codeDocument, ".mappings.txt");

            var serializedMappings = SourceMappingsSerializer.Serialize(document, codeDocument.Source);

            if (GenerateBaselines)
            {
                var baselineFullPath = Path.Combine(TestProjectRoot, baselineFilePath);
                Directory.CreateDirectory(Path.GetDirectoryName(baselineFullPath));
                WriteBaseline(actualCode, baselineFullPath);

                var baselineDiagnosticsFullPath = Path.Combine(TestProjectRoot, baselineDiagnosticsFilePath);
                var lines = document.Diagnostics.Select(RazorDiagnosticSerializer.Serialize).ToArray();
                if (lines.Any())
                {
                    WriteBaseline(lines, baselineDiagnosticsFullPath);
                }
                else if (File.Exists(baselineDiagnosticsFullPath))
                {
                    File.Delete(baselineDiagnosticsFullPath);
                }

                var baselineMappingsFullPath = Path.Combine(TestProjectRoot, baselineMappingsFilePath);
                var text = SourceMappingsSerializer.Serialize(document, codeDocument.Source);
                if (!string.IsNullOrEmpty(text))
                {
                    WriteBaseline(text, baselineMappingsFullPath);
                }
                else if (File.Exists(baselineMappingsFullPath))
                {
                    File.Delete(baselineMappingsFullPath);
                }

                return;
            }

            var codegenFile = TestFile.Create(baselineFilePath, GetType().Assembly);

            if (!codegenFile.Exists())
            {
                throw new XunitException($"The resource {baselineFilePath} was not found.");
            }

            var baseline = codegenFile.ReadAllText();

            Assert.Equal(baseline, actualCode);

            var baselineDiagnostics = string.Empty;
            var diagnosticsFile     = TestFile.Create(baselineDiagnosticsFilePath, GetType().Assembly);

            if (diagnosticsFile.Exists())
            {
                baselineDiagnostics = diagnosticsFile.ReadAllText();
            }

            var actualDiagnostics = string.Concat(document.Diagnostics.Select(d => RazorDiagnosticSerializer.Serialize(d) + "\r\n"));

            Assert.Equal(baselineDiagnostics, actualDiagnostics);

            var baselineMappings = string.Empty;
            var mappingsFile     = TestFile.Create(baselineMappingsFilePath, GetType().Assembly);

            if (mappingsFile.Exists())
            {
                baselineMappings = mappingsFile.ReadAllText();
            }

            var actualMappings = SourceMappingsSerializer.Serialize(document, codeDocument.Source);

            actualMappings = actualMappings.Replace("\r", "").Replace("\n", "\r\n");
            Assert.Equal(baselineMappings, actualMappings);
        }
예제 #2
0
    protected void AssertSourceMappingsMatchBaseline(RazorCodeDocument codeDocument)
    {
        if (FileName == null)
        {
            var message = $"{nameof(AssertSourceMappingsMatchBaseline)} should only be called from an integration test ({nameof(FileName)} is null).";
            throw new InvalidOperationException(message);
        }

        var csharpDocument = codeDocument.GetCSharpDocument();

        Assert.NotNull(csharpDocument);

        var baselineFileName   = Path.ChangeExtension(FileName, ".mappings.txt");
        var serializedMappings = SourceMappingsSerializer.Serialize(csharpDocument, codeDocument.Source);

        if (GenerateBaselines)
        {
            var baselineFullPath = Path.Combine(TestProjectRoot, baselineFileName);
            File.WriteAllText(baselineFullPath, serializedMappings);
            return;
        }

        var testFile = TestFile.Create(baselineFileName, GetType().GetTypeInfo().Assembly);

        if (!testFile.Exists())
        {
            throw new XunitException($"The resource {baselineFileName} was not found.");
        }

        var baseline = testFile.ReadAllText();

        // Normalize newlines to match those in the baseline.
        var actualBaseline = serializedMappings.Replace("\r", "").Replace("\n", "\r\n");

        Assert.Equal(baseline, actualBaseline);

        var syntaxTree = codeDocument.GetSyntaxTree();
        var visitor    = new CodeSpanVisitor();

        visitor.Visit(syntaxTree.Root);

        var charBuffer = new char[codeDocument.Source.Length];

        codeDocument.Source.CopyTo(0, charBuffer, 0, codeDocument.Source.Length);
        var sourceContent = new string(charBuffer);

        var spans = visitor.CodeSpans;

        for (var i = 0; i < spans.Count; i++)
        {
            var span         = spans[i];
            var sourceSpan   = span.GetSourceSpan(codeDocument.Source);
            var expectedSpan = sourceContent.Substring(sourceSpan.AbsoluteIndex, sourceSpan.Length);

            // See #2593
            if (string.IsNullOrWhiteSpace(expectedSpan))
            {
                // For now we don't verify whitespace inside of a directive. We know that directives cheat
                // with how they bound whitespace/C#/markup to make completion work.
                if (span.FirstAncestorOrSelf <RazorDirectiveSyntax>() != null)
                {
                    continue;
                }
            }

            // See #2594
            if (string.Equals("@", expectedSpan))
            {
                // For now we don't verify an escaped transition. In some cases one of the @ tokens in @@foo
                // will be mapped as C# but will not be present in the output buffer because it's not actually C#.
                continue;
            }

            var found = false;
            for (var j = 0; j < csharpDocument.SourceMappings.Count; j++)
            {
                var mapping = csharpDocument.SourceMappings[j];
                if (mapping.OriginalSpan == sourceSpan)
                {
                    var actualSpan = csharpDocument.GeneratedCode.Substring(
                        mapping.GeneratedSpan.AbsoluteIndex,
                        mapping.GeneratedSpan.Length);

                    if (!string.Equals(expectedSpan, actualSpan, StringComparison.Ordinal))
                    {
                        throw new XunitException(
                                  $"Found the span {sourceSpan} in the output mappings but it contains " +
                                  $"'{EscapeWhitespace(actualSpan)}' instead of '{EscapeWhitespace(expectedSpan)}'.");
                    }

                    found = true;
                    break;
                }
            }

            if (!found)
            {
                throw new XunitException(
                          $"Could not find the span {sourceSpan} - containing '{EscapeWhitespace(expectedSpan)}' " +
                          $"in the output.");
            }
        }
    }