public override IEnumerable <object[]> GetData(MethodInfo testMethod) { // docs are copied to the output directory by a build task // so all relative paths, are relative to <Working Direcotry>\content var dirPath = Path.Combine("content", m_RelativeSourcePath); // iterate over all files and read the code samples from the markdown file foreach (var filePath in Directory.GetFiles(dirPath, "*.md")) { var relativeFilePath = Path.Combine(m_RelativeSourcePath, Path.GetFileName(filePath)); var text = File.ReadAllText(filePath); var markdownDocument = Markdown.Parse(text); var codeBlocks = markdownDocument.OfType <FencedCodeBlock>() .Where(IsCSharpCodeBlock) .ToArray(); foreach (var codeBlock in codeBlocks) { var codeSample = new CodeSample( relativeFilePath, // code sample starts in the second line of the fenced code block (first line is fence and info string) codeBlock.Line + 1, codeBlock.Lines.ToString()); yield return(new[] { codeSample }); } } }
public static Compilation GetCompilation(this CodeSample codeSample) { var syntaxTree = CSharpSyntaxTree.ParseText(codeSample.SourceCode); var assemblyName = "Compilation_" + Path.GetRandomFileName(); return(CSharpCompilation.Create( assemblyName, new[] { syntaxTree }, GetMetadataReferences(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))); }
public static void NoCompilationErrors(CodeSample codeSample) { var compilation = codeSample.GetCompilation(); var errors = compilation.GetDiagnostics() .Where(d => d.Severity >= DiagnosticSeverity.Error || d.IsWarningAsError) .ToArray(); string GetDiagnosticMessage(Diagnostic diagnostic) { // calculate the position of the error in the original input // document based on the location of the error within the source code // and the location of the source code within the document var location = diagnostic.Location.GetMappedLineSpan().StartLinePosition; // the line of the error within the original markdown document // is the line within the source code + the number of lines in // the document before the code block var line = location.Line + codeSample.Line; // both line and character are zero-based, so add 1 to make them one-based in // error message return($"{codeSample.RelativePath}({line + 1},{location.Character + 1}): {diagnostic.Id}: {diagnostic.GetMessage()}"); } if (errors.Length > 0) { throw new XunitException( "Compilation contains errors:\r\n" + errors .Select(GetDiagnosticMessage) .Select(x => " " + x) .JoinToString("\r\n") ); } }