public async void Files_are_merged_in_order() { var processor = new CodeMergeTransformer(); var workspace = new Workspace( workspaceType: "console", files: new[] { new File("fileA.cs", "first line;", 0), new File("fileA.cs", "third line;", 2), new File("fileA.cs", "second line;", 1), new File("fileB.cs", "first line;", 2), new File("fileB.cs", "third line;", 0), new File("fileB.cs", "second line;", 1) } ); var processed = await processor.TransformAsync(workspace); processed.Should().NotBeNull(); var fileA = processed.Files.Single(f => f.Name == "fileA.cs"); fileA.Text.Should() .Match(@"first line; second line; third line;".EnforceLF()); var fileB = processed.Files.Single(f => f.Name == "fileB.cs"); fileB.Text.Should() .Match(@"third line; second line; first line;".EnforceLF()); }
public void When_workspace_is_null_then_the_transformer_throw_exception() { var processor = new CodeMergeTransformer(); Func <Task> extraction = () => processor.TransformAsync(null); extraction.Should().Throw <ArgumentNullException>(); }
public async void buffers_are_merged_in_order() { var processor = new CodeMergeTransformer(); var workspace = new Workspace( workspaceType: "console", buffers: new[] { new Buffer(new BufferId("fileA.cs", "regionA"), "first line;", order: 0), new Buffer(new BufferId("fileA.cs", "regionA"), "third line;", order: 2), new Buffer(new BufferId("fileA.cs", "regionA"), "second line;", order: 1), new Buffer(new BufferId("fileA.cs", "regionB"), "fourth line;", order: 0), new Buffer(new BufferId("fileA.cs", "regionB"), "sixth line;", order: 2), new Buffer(new BufferId("fileA.cs", "regionB"), "fifth line;", order: 1), new Buffer("fileB.cs", "first line;", order: 2), new Buffer("fileB.cs", "third line;", order: 0), new Buffer("fileB.cs", "second line;", order: 1) } ); var processed = await processor.TransformAsync(workspace); processed.Should().NotBeNull(); var bufferARegionA = processed.Buffers.Single(f => f.Id == new BufferId("fileA.cs", "regionA")); bufferARegionA.Content.Should() .Match(@"first line; second line; third line;".EnforceLF()); var bufferARegionB = processed.Buffers.Single(f => f.Id == new BufferId("fileA.cs", "regionB")); bufferARegionB.Content.Should() .Match(@"fourth line; fifth line; sixth line;".EnforceLF()); var bufferB = processed.Buffers.Single(f => f.Id == "fileB.cs"); bufferB.Content.Should() .Match(@"third line; second line; first line;".EnforceLF()); }
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}"); } } }