예제 #1
0
    /// <summary>
    /// Verifies the output of a source generator.
    /// </summary>
    /// <typeparam name="TGenerator">The generator type to use.</typeparam>
    /// <param name="source">The input source to process.</param>
    /// <param name="index">The target index to check in the resulting output.</param>
    /// <param name="expectedBody">The expected body to compare with the generated code.</param>
    private static void VerifyGeneratedMethodLines <TGenerator>(string source, int index, string expectedBody)
        where TGenerator : class, IIncrementalGenerator, new()
    {
        SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source);

        IEnumerable <MetadataReference> references =
            from assembly in AppDomain.CurrentDomain.GetAssemblies()
            where !assembly.IsDynamic
            let reference = MetadataReference.CreateFromFile(assembly.Location)
                            select reference;

        CSharpCompilation compilation = CSharpCompilation.Create("original", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

        IIncrementalGenerator generator = new TGenerator();

        CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(generator);

        driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray <Diagnostic> diagnostics);

        string outputBody = outputCompilation.SyntaxTrees.Skip(index + 1).First().ToString();

        string[] outputLines   = outputBody.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        string[] expectedLines = expectedBody.Replace("\r", "").Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);

        Assert.AreEqual(expectedLines.Length, outputLines.Length);

        for (int i = 0; i < outputLines.Length; i++)
        {
            Assert.AreEqual(expectedLines[i], outputLines[i]);
        }
    }
예제 #2
0
        /// <summary>
        /// Verifies the output of a source generator.
        /// </summary>
        /// <typeparam name="TGenerator">The generator type to use.</typeparam>
        /// <param name="syntaxTree">The input source tree to process.</param>
        /// <param name="diagnosticsIds">The diagnostic ids to expect for the input source code.</param>
        private static void VerifyGeneratedDiagnostics <TGenerator>(SyntaxTree syntaxTree, params string[] diagnosticsIds)
            where TGenerator : class, ISourceGenerator, new()
        {
            Type observableObjectType    = typeof(ObservableObject);
            Type validationAttributeType = typeof(ValidationAttribute);

            IEnumerable <MetadataReference> references =
                from assembly in AppDomain.CurrentDomain.GetAssemblies()
                where !assembly.IsDynamic
                let reference = MetadataReference.CreateFromFile(assembly.Location)
                                select reference;

            CSharpCompilation compilation = CSharpCompilation.Create(
                "original",
                new SyntaxTree[] { syntaxTree },
                references,
                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            ISourceGenerator generator = new TGenerator();

            CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: (CSharpParseOptions)syntaxTree.Options);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray <Diagnostic> diagnostics);

            HashSet <string> resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet();

            Assert.IsTrue(resultingIds.SetEquals(diagnosticsIds));

            GC.KeepAlive(observableObjectType);
            GC.KeepAlive(validationAttributeType);
        }
예제 #3
0
        private void VerifyGeneratedMethodLines(string source, string expectedEnumName, string expectedBody)
        {
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source);

            List <MetadataReference> references = new List <MetadataReference>();

            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly assembly in assemblies)
            {
                if (!assembly.IsDynamic)
                {
                    references.Add(MetadataReference.CreateFromFile(assembly.Location));
                }
            }

            CSharpCompilation compilation = CSharpCompilation.Create("original", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            ISourceGenerator generator = new EnumValidationGenerator();

            CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(generator);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray <Diagnostic> diagnostics);
            Assert.False(diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error), "Failed: " + diagnostics.FirstOrDefault()?.GetMessage());

            string output = outputCompilation.SyntaxTrees.Skip(1).First().ToString();

            List <string> lines = output.Split("\r\n").ToList();

            AssertFirstLineAndRemove(lines, "// <auto-generated />");
            AssertFirstLineAndRemove(lines, "namespace SourceGenerated");
            AssertFirstLineAndRemove(lines, "{");
            AssertFirstLineAndRemove(lines, "internal static partial class EnumValidator");
            AssertFirstLineAndRemove(lines, "{");

            AssertFirstLineAndRemove(lines, "/// <summary>Validates that the enum value passed in is valid for the enum type.</summary>");
            AssertFirstLineAndRemove(lines, $"public static void Validate({expectedEnumName} enumToValidate, string parameterName = \"value\")");
            AssertFirstLineAndRemove(lines, "{");
            AssertFirstLineAndRemove(lines, "int intValue = (int)enumToValidate;");

            foreach (string line in expectedBody.Split("\r\n"))
            {
                AssertFirstLineAndRemove(lines, line.Trim());
            }

            AssertFirstLineAndRemove(lines, $"ReportEnumValidationError(parameterName, intValue, typeof({expectedEnumName}));");

            AssertFirstLineAndRemove(lines, "}");
예제 #4
0
        /// <summary>
        /// Performs a test on all <see cref="ISourceGenerator"/>s registered in the provided <paramref name="generatorDriver"/>.
        /// </summary>
        /// <param name="generatorDriver"><see cref="CSharpGeneratorDriver"/> to run a tests on all registered <see cref="ISourceGenerator"/> of.</param>
        /// <param name="resultProvider">A delegate that creates the target <see cref="IGeneratorTestResult"/> from the data provided by the tested <paramref name="generatorDriver"/>.</param>
        /// <param name="compilation">A <see cref="CSharpCompilation"/> to be used a input of the tested <paramref name="generatorDriver"/>.</param>
        /// <exception cref="ArgumentNullException"><paramref name="generatorDriver"/> is <see langword="null"/>. -or- <paramref name="resultProvider"/> is <see langword="null"/>. -or- <paramref name="compilation"/> is <see langword="null"/>.</exception>
        public static IGeneratorTestResult RunTest(this CSharpGeneratorDriver generatorDriver, GeneratorTestResultProvider resultProvider, CSharpCompilation compilation)
        {
            if (generatorDriver is null)
            {
                throw new ArgumentNullException(nameof(generatorDriver));
            }

            if (resultProvider is null)
            {
                throw new ArgumentNullException(nameof(resultProvider));
            }

            if (compilation is null)
            {
                throw new ArgumentNullException(nameof(compilation));
            }

            CSharpGeneratorDriver driver = generatorDriver;

            driver = (CSharpGeneratorDriver)driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out _);
            return(resultProvider(driver, compilation, (CSharpCompilation)outputCompilation));
        }
예제 #5
0
    /// <summary>
    /// Verifies the output of a source generator.
    /// </summary>
    /// <typeparam name="TGenerator">The generator type to use.</typeparam>
    /// <param name="source">The input source to process.</param>
    /// <param name="diagnosticsIds">The expected diagnostics ids to be generated.</param>
    private static void VerifyGeneratedDiagnostics <TGenerator>(string source, params string[] diagnosticsIds)
        where TGenerator : class, IIncrementalGenerator, new()
    {
        SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source);

        IEnumerable <MetadataReference> references =
            from assembly in AppDomain.CurrentDomain.GetAssemblies()
            where !assembly.IsDynamic
            let reference = MetadataReference.CreateFromFile(assembly.Location)
                            select reference;

        CSharpCompilation compilation = CSharpCompilation.Create("original", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

        IIncrementalGenerator generator = new TGenerator();

        CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(generator);

        driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray <Diagnostic> diagnostics);

        HashSet <string> resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet();

        Assert.IsTrue(resultingIds.SetEquals(diagnosticsIds));
    }