Пример #1
0
        public void When_workspace_is_null_then_the_transformer_throw_exception()
        {
            var         processor  = new BufferInliningTransformer();
            Func <Task> extraction = () => processor.TransformAsync(null);

            extraction.Should().Throw <ArgumentNullException>();
        }
Пример #2
0
        public async Task Buffer_can_be_injected_before_region()
        {
            var original = new Workspace(
                files: new[]
            {
                new Protocol.File("Program.cs", SourceCodeProvider.ConsoleProgramSingleRegion)
            },
                buffers: new[]
            {
                new Buffer("Program.cs@alpha[before]", "var newValue = 1000;".EnforceLF())
            });
            var processor = new BufferInliningTransformer();

            var processed = await processor.TransformAsync(original);

            processed.Should().NotBeNull();
            processed.Files.Should().NotBeEmpty();
            var newCode = processed.Files.ElementAt(0).Text;

            newCode.Should().NotBe(original.Files.ElementAt(0).Text);
            newCode.Should().Contain("var newValue = 1000;");
            newCode.Should().Contain("var a = 10;");

            original.Buffers.ElementAt(0).Position.Should().Be(0);
            processed.Buffers.Length.Should().Be(original.Buffers.Length);
            processed.Buffers.ElementAt(0).Position.Should().Be(original.Buffers.ElementAt(0).Position);
            processed.Buffers.ElementAt(0).AbsolutePosition.Should().Be(155);
        }
Пример #3
0
        public async Task Processed_workspace_files_are_replaced_by_buffer_when_id_is_just_file_name()
        {
            var ws = new Workspace(
                files: new[]
            {
                new Protocol.File("Program.cs", SourceCodeProvider.ConsoleProgramSingleRegion)
            },
                buffers: new[]
            {
                new Buffer("Program.cs", "var newValue = 1000;", 0)
            });
            var processor = new BufferInliningTransformer();

            var processed = await processor.TransformAsync(ws);

            processed.Should().NotBeNull();
            processed.Files.Should().NotBeEmpty();
            var newCode = processed.Files.ElementAt(0).Text;

            newCode.Should().NotBe(ws.Files.ElementAt(0).Text);
            newCode.Should().Be("var newValue = 1000;");

            processed.Buffers.Length.Should().Be(ws.Buffers.Length);
            processed.Buffers.ElementAt(0).Position.Should().Be(0);
        }
Пример #4
0
        public async Task Processed_workspace_with_single_buffer_with_empty_id_generates_a_program_file()
        {
            var ws = new Workspace(
                buffers: new[]
            {
                new Buffer("", SourceCodeProvider.ConsoleProgramSingleRegion, 0)
            });
            var processor = new BufferInliningTransformer();

            var processed = await processor.TransformAsync(ws);

            processed.Should().NotBeNull();
            processed.Files.Should().NotBeEmpty();
            var newCode = processed.Files.ElementAt(0).Text;

            newCode.Should().Contain(SourceCodeProvider.ConsoleProgramSingleRegion);
        }
Пример #5
0
        public async Task If_workspace_contains_with_multiple_buffers_targeting_single_file_generates_a_single_file()
        {
            var expectedCode = @"using System;

namespace ConsoleProgramSingleRegion
{
    public class Program
    {
        public static void Main(string[] args)
        {
            #region alpha
var newValueA = ""as string"";
Console.Write(newValueA);
#endregion

            #region beta
var newValueB = ""as different string"";
Console.Write(newValueA + newValueB);
#endregion
        }
    }
}".EnforceLF();

            var ws = new Workspace(
                files: new[]
            {
                new Protocol.File("Program.cs", SourceCodeProvider.ConsoleProgramMultipleRegions)
            },
                buffers: new[]
            {
                new Buffer(new BufferId("Program.cs", "alpha"), "var newValueA = \"as string\";\nConsole.Write(newValueA);", 0),
                new Buffer(new BufferId("Program.cs", "beta"), "var newValueB = \"as different string\";\nConsole.Write(newValueA + newValueB);", 0)
            });
            var processor = new BufferInliningTransformer();

            var processed = await processor.TransformAsync(ws);

            processed.Should().NotBeNull();
            processed.Files.Should().NotBeEmpty();
            var newCode = processed.Files.ElementAt(0).Text.EnforceLF();

            newCode.Should().Be(expectedCode);
        }
Пример #6
0
        public async Task If_workspace_contains_buffers_whose_file_names_are_absolute_paths_the_contents_are_read_from_disk()
        {
            using (var directory = DisposableDirectory.Create())
            {
                var filePath    = Path.Combine(directory.Directory.FullName, "Program.cs");
                var fileContent =
                    @"using System;
namespace Code{{
    public static class Program{{
        public static void Main(){{
        #region region one
        #endregion
        }}
    }}
}}".EnforceLF();
                var expectedFileContent =
                    @"using System;
namespace Code{{
    public static class Program{{
        public static void Main(){{
        #region region one
Console.Write(2);
#endregion
        }}
    }}
}}".EnforceLF();

                File.WriteAllText(filePath, fileContent);
                var ws = new Workspace(
                    buffers: new[]
                {
                    new Buffer(new BufferId(filePath, "region one"), "Console.Write(2);"),
                }
                    );

                var processor = new BufferInliningTransformer();
                var processed = await processor.TransformAsync(ws);

                processed.Files[0].Text.EnforceLF().Should().Be(expectedFileContent);
            }
        }
Пример #7
0
        public async Task If_workspace_contains_files_whose_names_are_absolute_paths_and_they_have_no_content_then_the_contents_are_read_from_disk()
        {
            using (var directory = DisposableDirectory.Create())
            {
                var filePath = Path.Combine(directory.Directory.FullName, "Program.cs");
                var content  =
                    @"using System;";
                File.WriteAllText(filePath, content);
                var ws = new Workspace(
                    files: new[]
                {
                    new Protocol.File(filePath, null)
                }
                    );

                var processor = new BufferInliningTransformer();
                var processed = await processor.TransformAsync(ws);

                processed.Files[0].Text.Should().Be(content);
            }
        }
Пример #8
0
        public async Task Buffers_can_be_injected_according_to_injection_points()
        {
            var original = new Workspace(
                files: new[]
            {
                new Protocol.File("Program.cs", SourceCodeProvider.ConsoleProgramSingleRegion)
            },
                buffers: new[]
            {
                new Buffer("Program.cs@alpha[before]", "var before = 1000;".EnforceLF()),
                new Buffer("Program.cs@alpha[after]", "var after = 1000;".EnforceLF()),
                new Buffer("Program.cs@alpha", "var inlined = 1000;".EnforceLF())
            });
            var processor = new BufferInliningTransformer();

            var processed = await processor.TransformAsync(original);

            processed.Should().NotBeNull();
            processed.Files.Should().NotBeEmpty();
            var newCode = processed.Files.ElementAt(0).Text;

            newCode.Should().NotBe(original.Files.ElementAt(0).Text);
            newCode.Should().Contain("var before = 1000;");
            newCode.Should().Contain("var inlined = 1000;");
            newCode.Should().Contain("var after = 1000;");

            var beforeBuffer = processed.Buffers.First(b => b.Id.RegionName.Contains("before"));

            beforeBuffer.AbsolutePosition.Should().Be(155);

            var inlinedBuffer = processed.Buffers.First(b => b.Id.RegionName == "alpha");

            inlinedBuffer.AbsolutePosition.Should().Be(188);

            var afterBuffer = processed.Buffers.First(b => b.Id.RegionName.Contains("after"));

            afterBuffer.AbsolutePosition.Should().Be(235);
        }
Пример #9
0
        public static async Task <int> Do(
            VerifyOptions verifyOptions,
            IConsole console,
            StartupOptions startupOptions = null)
        {
            var directoryAccessor = verifyOptions.RootDirectory;
            var packageRegistry   = PackageRegistry.CreateForTryMode(directoryAccessor);
            var markdownProject   = new MarkdownProject(
                directoryAccessor,
                packageRegistry,
                startupOptions);
            var errorCount      = 0;
            var workspaceServer = new Lazy <IWorkspaceServer>(() => new WorkspaceServerMultiplexer(packageRegistry));

            var markdownFiles = markdownProject.GetAllMarkdownFiles().ToArray();

            if (markdownFiles.Length == 0)
            {
                console.Error.WriteLine($"No markdown files found under {directoryAccessor.GetFullyQualifiedRoot()}");
                return(-1);
            }

            foreach (var markdownFile in markdownFiles)
            {
                var fullName = directoryAccessor.GetFullyQualifiedPath(markdownFile.Path).FullName;
                var markdownFileDirectoryAccessor = directoryAccessor.GetDirectoryAccessorForRelativePath(markdownFile.Path.Directory);

                console.Out.WriteLine();
                console.Out.WriteLine(fullName);
                console.Out.WriteLine(new string('-', fullName.Length));

                var codeLinkBlocks = await markdownFile.GetAnnotatedCodeBlocks();

                var sessions = codeLinkBlocks.GroupBy(block => block.Annotations?.Session);

                foreach (var session in sessions)
                {
                    if (session.Select(block => block.ProjectOrPackageName()).Distinct().Count() != 1)
                    {
                        SetError();
                        console.Out.WriteLine($"Session cannot span projects or packages: --session {session.Key}");
                        continue;
                    }

                    foreach (var codeLinkBlock in session)
                    {
                        ReportCodeLinkageResults(codeLinkBlock, markdownFileDirectoryAccessor);
                    }

                    Console.ResetColor();

                    if (!session.Any(block => block.Diagnostics.Any()))
                    {
                        var(buffersToInclude, filesToInclude) = await markdownFile.GetIncludes(markdownFileDirectoryAccessor);

                        await ReportCompileResults(
                            session,
                            markdownFile,
                            filesToInclude,
                            buffersToInclude,
                            markdownFileDirectoryAccessor);
                    }

                    Console.ResetColor();
                }
            }

            if (errorCount > 0)
            {
                SetError(false);
            }
            else
            {
                SetOk();
            }

            console.Out.WriteLine($"\n\ndotnet try verify found {errorCount} error(s)");

            Console.ResetColor();

            return(errorCount == 0
                       ? 0
                       : 1);

            void SetError(bool incrementCount = true)
            {
                Console.ForegroundColor = ConsoleColor.Red;

                if (incrementCount)
                {
                    errorCount++;
                }
            }

            void SetOk()
            {
                Console.ForegroundColor = ConsoleColor.Green;
            }

            async Task ReportCompileResults(
                IGrouping <string, AnnotatedCodeBlock> session,
                MarkdownFile markdownFile,
                Dictionary <string, File[]> filesToInclude,
                IReadOnlyDictionary <string, Buffer[]> buffersToInclude,
                IDirectoryAccessor accessor)
            {
                var description = session.Count() == 1 || string.IsNullOrWhiteSpace(session.Key)
                                      ? $"region \"{session.Select(s => s.Annotations.Region).Distinct().First()}\""
                                      : $"session \"{session.Key}\"";

                console.Out.WriteLine($"\n  Compiling samples for {description}\n");

                var projectOrPackageName = session
                                           .Select(b => b.ProjectOrPackageName())
                                           .FirstOrDefault(name => !string.IsNullOrWhiteSpace(name));

                var language = session
                               .Select(b => b.Language())
                               .FirstOrDefault(name => !string.IsNullOrWhiteSpace(name));

                if (!ProjectIsCompatibleWithLanguage(new UriOrFileInfo(projectOrPackageName), language))
                {
                    SetError();

                    console.Out.WriteLine($"    Build failed as project {projectOrPackageName} is not compatible with language {language}");
                }

                var editableCodeBlocks = session.Where(b => b.Annotations.Editable).ToList();

                var buffers = editableCodeBlocks
                              .Select(block => block.GetBufferAsync(accessor, markdownFile))
                              .ToList();

                var files = new List <File>();

                if (filesToInclude.TryGetValue("global", out var globalIncludes))
                {
                    files.AddRange(globalIncludes);
                }

                if (!string.IsNullOrWhiteSpace(session.Key) && filesToInclude.TryGetValue(session.Key, out var sessionIncludes))
                {
                    files.AddRange(sessionIncludes);
                }

                if (buffersToInclude.TryGetValue("global", out var globalSessionBuffersToInclude))
                {
                    buffers.AddRange(globalSessionBuffersToInclude);
                }

                if (!string.IsNullOrWhiteSpace(session.Key) && buffersToInclude.TryGetValue(session.Key, out var localSessionBuffersToInclude))
                {
                    buffers.AddRange(localSessionBuffersToInclude);
                }

                var workspace = new Workspace(
                    workspaceType: projectOrPackageName,
                    language: language,
                    files: files.ToArray(),
                    buffers: buffers.ToArray());

                var mergeTransformer    = new CodeMergeTransformer();
                var inliningTransformer = new BufferInliningTransformer();

                var processed = await mergeTransformer.TransformAsync(workspace);

                processed = await inliningTransformer.TransformAsync(processed);

                processed = new Workspace(usings: processed.Usings, workspaceType: processed.WorkspaceType, language: processed.Language, files: processed.Files);

                var result = await workspaceServer.Value.Compile(new WorkspaceRequest(processed));

                var projectDiagnostics = result.GetFeature <ProjectDiagnostics>()
                                         .Where(e => e.Severity == DiagnosticSeverity.Error)
                                         .ToArray();

                if (projectDiagnostics.Any())
                {
                    SetError();

                    console.Out.WriteLine($"    Build failed for project {projectOrPackageName}");

                    foreach (var diagnostic in projectDiagnostics)
                    {
                        console.Out.WriteLine($"\t\t{diagnostic.Location}: {diagnostic.Message}");
                    }
                }
                else
                {
                    var symbol = !result.Succeeded
                                     ? "X"
                                     : "✓";

                    if (result.Succeeded)
                    {
                        SetOk();
                        console.Out.WriteLine($"    {symbol}  No errors found within samples for {description}");
                    }
                    else
                    {
                        SetError();

                        console.Out.WriteLine($"    {symbol}  Errors found within samples for {description}");

                        foreach (var diagnostic in result.GetFeature <Diagnostics>())
                        {
                            console.Out.WriteLine($"\t\t{diagnostic.Message}");
                        }
                    }
                }
            }

            void ReportCodeLinkageResults(
                AnnotatedCodeBlock codeLinkBlock,
                IDirectoryAccessor accessor)
            {
                var diagnostics = codeLinkBlock.Diagnostics.ToArray();

                Console.ResetColor();

                console.Out.WriteLine("  Checking Markdown...");

                if (diagnostics.Any())
                {
                    SetError();
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                }

                var blockOptions = (LocalCodeBlockAnnotations)codeLinkBlock.Annotations;

                var file = blockOptions?.SourceFile ?? blockOptions?.DestinationFile;
                var fullyQualifiedPath =
                    file != null
                        ? accessor.GetFullyQualifiedPath(file).FullName
                        : "UNKNOWN";

                var project = codeLinkBlock.ProjectOrPackageName() ?? "UNKNOWN";

                var symbol = diagnostics.Any()
                                 ? "X"
                                 : "✓";

                console.Out.WriteLine($"    {symbol}  Line {codeLinkBlock.Line + 1}:\t{fullyQualifiedPath} (in project {project})");

                foreach (var diagnostic in diagnostics)
                {
                    console.Out.WriteLine($"\t\t{diagnostic}");
                }
            }
        }