Esempio n. 1
0
        public void Compile_RunsCallback()
        {
            var content = "public class MyTestType  {}";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter        = CompilationServices.Default.LibraryExporter;
            RoslynCompilationContext usedCompilation = null;
            var mvcRazorHost = new Mock <IMvcRazorHost>();

            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
            .Returns(string.Empty);

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost.Object,
                GetOptions(callback: c => usedCompilation = c),
                GetFileProviderAccessor(),
                NullLoggerFactory.Instance);

            var relativeFileInfo = new RelativeFileInfo(
                new TestFileInfo {
                PhysicalPath = "SomePath"
            },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            Assert.NotNull(usedCompilation);
            Assert.NotNull(usedCompilation.Compilation);
            Assert.Equal(1, usedCompilation.Compilation.SyntaxTrees.Length);
        }
Esempio n. 2
0
 /// <summary>
 /// Initializes a new instance of <see cref="CompilerCacheEntry"/> for a file that was dynamically compiled.
 /// </summary>
 /// <param name="info">Metadata about the file that was compiled.</param>
 /// <param name="compiledType">The compiled <see cref="Type"/>.</param>
 public CompilerCacheEntry([NotNull] RelativeFileInfo info, [NotNull] Type compiledType)
 {
     CompiledType = compiledType;
     RelativePath = info.RelativePath;
     Length       = info.FileInfo.Length;
     LastModified = info.FileInfo.LastModified;
 }
        public void Compile_ReturnsUncachedCompilationResultWithCompiledContent()
        {
            // Arrange
            var content = @"
public class MyTestType  {}";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor = GetLoadContextAccessor();
            var libraryExporter = GetLibraryExporter();

            var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
                                   .Returns(new CompilerOptions());
            var mvcRazorHost = new Mock<IMvcRazorHost>();
            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
                        .Returns(string.Empty);

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryExporter,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost.Object,
                                                                  GetOptions());
            var relativeFileInfo = new RelativeFileInfo(new TestFileInfo { PhysicalPath = "SomePath" },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            var uncachedResult = Assert.IsType<UncachedCompilationResult>(result);
            Assert.Equal("MyTestType", result.CompiledType.Name);
            Assert.Equal(content, uncachedResult.CompiledContent);
        }
Esempio n. 4
0
        public void Compile_ReturnsSingleTypeThatStartsWithMainClassNamePrefix()
        {
            // Arrange
            var content = @"
public class RazorPrefixType  {}
public class NotRazorPrefixType {}";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter        = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost           = new Mock <IMvcRazorHost>();

            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
            .Returns("RazorPrefix");

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost.Object,
                GetOptions(),
                GetFileProviderAccessor(),
                NullLoggerFactory.Instance);

            var relativeFileInfo = new RelativeFileInfo(
                new TestFileInfo {
                PhysicalPath = "SomePath"
            },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.NotNull(result.CompiledType);
            Assert.Equal("RazorPrefixType", result.CompiledType.Name);
        }
        /// <inheritdoc />
        public CompilationResult Compile(RelativeFileInfo file)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            GeneratorResults results;

            using (var inputStream = file.FileInfo.CreateReadStream())
            {
                _logger.RazorFileToCodeCompilationStart(file.RelativePath);

                var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;

                results = GenerateCode(file.RelativePath, inputStream);

                _logger.RazorFileToCodeCompilationEnd(file.RelativePath, startTimestamp);
            }

            if (!results.Success)
            {
                return(GetCompilationFailedResult(file, results.ParserErrors));
            }

            return(_compilationService.Compile(file, results.GeneratedCode));
        }
Esempio n. 6
0
        public void Compile_ReturnsGeneratedCodePath_IfLinePragmaIsNotAvailable()
        {
            // Arrange
            var fileContent            = "file content";
            var content                = @"this should fail";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter        = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost           = Mock.Of <IMvcRazorHost>();

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost,
                GetOptions(),
                GetFileProviderAccessor(),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(
                new TestFileInfo {
                Content = fileContent
            },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType <CompilationResult>(result);
            Assert.Null(result.CompiledType);

            var compilationFailure = Assert.Single(result.CompilationFailures);

            Assert.Equal("Generated Code", compilationFailure.SourceFilePath);
            Assert.Equal(content, compilationFailure.SourceFileContent);
        }
Esempio n. 7
0
        public void CompileCalculatesRootRelativePath(string appPath, string viewPath)
        {
            // Arrange
            var host = new Mock <IMvcRazorHost>();

            host.Setup(h => h.GenerateCode(@"Views\index\home.cshtml", It.IsAny <Stream>()))
            .Returns(GetGeneratorResult())
            .Verifiable();

            var fileInfo = new Mock <IFileInfo>();

            fileInfo.Setup(f => f.PhysicalPath).Returns(viewPath);
            fileInfo.Setup(f => f.CreateReadStream()).Returns(Stream.Null);

            var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");

            var compiler = new Mock <ICompilationService>();

            compiler.Setup(c => c.Compile(relativeFileInfo, It.IsAny <string>()))
            .Returns(CompilationResult.Successful(typeof(RazorCompilationServiceTest)));

            var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions());

            // Act
            razorService.Compile(relativeFileInfo);

            // Assert
            host.Verify();
        }
        public void Compile_ReturnsCompilationResult()
        {
            // Arrange
            var content = @"
public class MyTestType  {}";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost = new Mock<IMvcRazorHost>();
            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
                        .Returns(string.Empty);

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost.Object,
                GetOptions(),
                GetFileProviderAccessor(),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(
                new TestFileInfo { PhysicalPath = "SomePath" },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.Equal("MyTestType", result.CompiledType.Name);
        }
        public void CompileCalculatesRootRelativePath(string appPath, string viewPath)
        {
            // Arrange
            var host = new Mock<IMvcRazorHost>();
            host.Setup(h => h.GenerateCode(@"Views\index\home.cshtml", It.IsAny<Stream>()))
                .Returns(GetGeneratorResult())
                .Verifiable();

            var fileInfo = new Mock<IFileInfo>();
            fileInfo.Setup(f => f.PhysicalPath).Returns(viewPath);
            fileInfo.Setup(f => f.CreateReadStream()).Returns(Stream.Null);

            var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");

            var compiler = new Mock<ICompilationService>();
            compiler.Setup(c => c.Compile(relativeFileInfo, It.IsAny<string>()))
                    .Returns(CompilationResult.Successful(typeof(RazorCompilationServiceTest)));

            var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions());

            // Act
            razorService.Compile(relativeFileInfo);

            // Assert
            host.Verify();
        }
        /// <inheritdoc />
        public CompilationResult Compile(RelativeFileInfo file)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            GeneratorResults results;
            using (var inputStream = file.FileInfo.CreateReadStream())
            {
                _logger.RazorFileToCodeCompilationStart(file.RelativePath);

                var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;

                results = GenerateCode(file.RelativePath, inputStream);

                _logger.RazorFileToCodeCompilationEnd(file.RelativePath, startTimestamp);
            }

            if (!results.Success)
            {
                return GetCompilationFailedResult(file, results.ParserErrors);
            }

            return _compilationService.Compile(file, results.GeneratedCode);
        }
        // Internal for unit testing
        internal CompilationResult GetCompilationFailedResult(RelativeFileInfo file, IEnumerable <RazorError> errors)
        {
            // If a SourceLocation does not specify a file path, assume it is produced
            // from parsing the current file.
            var messageGroups = errors
                                .GroupBy(razorError =>
                                         razorError.Location.FilePath ?? file.RelativePath,
                                         StringComparer.Ordinal);

            var failures = new List <CompilationFailure>();

            foreach (var group in messageGroups)
            {
                var filePath           = group.Key;
                var fileContent        = ReadFileContentsSafely(filePath);
                var compilationFailure = new CompilationFailure(
                    filePath,
                    fileContent,
                    compiledContent: string.Empty,
                    messages: group.Select(parserError => CreateDiagnosticMessage(parserError, filePath)));
                failures.Add(compilationFailure);
            }

            return(new CompilationResult(failures));
        }
Esempio n. 12
0
        private CompilerCacheResult CreateCacheEntry(
            string normalizedPath,
            Func <RelativeFileInfo, CompilationResult> compile)
        {
            CompilerCacheResult cacheResult;
            var fileInfo = _fileProvider.GetFileInfo(normalizedPath);
            MemoryCacheEntryOptions cacheEntryOptions;
            CompilerCacheResult     cacheResultToCache;

            if (!fileInfo.Exists)
            {
                cacheResultToCache = CompilerCacheResult.FileNotFound;
                cacheResult        = CompilerCacheResult.FileNotFound;

                cacheEntryOptions = new MemoryCacheEntryOptions();
                cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(normalizedPath));
            }
            else
            {
                var relativeFileInfo  = new RelativeFileInfo(fileInfo, normalizedPath);
                var compilationResult = compile(relativeFileInfo).EnsureSuccessful();
                cacheEntryOptions = GetMemoryCacheEntryOptions(normalizedPath);

                // By default the CompilationResult returned by IRoslynCompiler is an instance of
                // UncachedCompilationResult. This type has the generated code as a string property and do not want
                // to cache it. We'll instead cache the unwrapped result.
                cacheResultToCache = new CompilerCacheResult(
                    CompilationResult.Successful(compilationResult.CompiledType));
                cacheResult = new CompilerCacheResult(compilationResult);
            }

            _cache.Set(normalizedPath, cacheResultToCache, cacheEntryOptions);
            return(cacheResult);
        }
        public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
        {
            // Arrange
            var viewPath = "some-relative-path";
            var fileContent = "test file content";
            var content = $@"
#line 1 ""{viewPath}""
this should fail";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost = Mock.Of<IMvcRazorHost>();
            var fileProvider = new TestFileProvider();
            var fileInfo = fileProvider.AddFile(viewPath, fileContent);

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost,
                GetOptions(),
                GetFileProviderAccessor(fileProvider),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
            Assert.Equal(fileContent, compilationFailure.SourceFileContent);
        }
Esempio n. 14
0
        public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
        {
            // Arrange
            var viewPath               = "some-relative-path";
            var fileContent            = "test file content";
            var content                = $@"
#line 1 ""{viewPath}""
this should fail";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter        = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost           = Mock.Of <IMvcRazorHost>();
            var fileProvider           = new TestFileProvider();
            var fileInfo               = fileProvider.AddFile(viewPath, fileContent);

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost,
                GetOptions(),
                GetFileProviderAccessor(fileProvider),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType <CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);

            Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
            Assert.Equal(fileContent, compilationFailure.SourceFileContent);
        }
Esempio n. 15
0
        /// <inheritdoc />
        public CompilationResult Compile([NotNull] RelativeFileInfo file)
        {
            GeneratorResults results;

            using (var inputStream = file.FileInfo.CreateReadStream())
            {
                results = _razorHost.GenerateCode(file.RelativePath, inputStream);
            }

            if (!results.Success)
            {
                return(GetCompilationFailedResult(file, results.ParserErrors));
            }

            return(_compilationService.Compile(file, results.GeneratedCode));
        }
        public void Compile_DoesNotThrow_IfFileCannotBeRead()
        {
            // Arrange
            var path    = "some-relative-path";
            var content = $@"
#line 1 ""{path}""
this should fail";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor       = GetLoadContextAccessor();
            var libraryManager = GetLibraryManager();

            var compilerOptionsProvider = new Mock <ICompilerOptionsProvider>();

            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
            .Returns(new CompilerOptions());
            var mvcRazorHost = Mock.Of <IMvcRazorHost>();

            var mockFileInfo = new Mock <IFileInfo>();

            mockFileInfo.Setup(f => f.CreateReadStream())
            .Throws(new Exception());
            var fileProvider = new TestFileProvider();

            fileProvider.AddFile(path, mockFileInfo.Object);

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryManager,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost,
                                                                  GetOptions(fileProvider));

            var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType <CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);

            Assert.Equal(path, compilationFailure.SourceFilePath);
            Assert.Null(compilationFailure.SourceFileContent);
        }
        public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation()
        {
            // Arrange
            var content = @"
#if MY_CUSTOM_DEFINE
public class MyCustomDefinedClass {}
#else
public class MyNonCustomDefinedClass {}
#endif
";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor       = GetLoadContextAccessor();
            var libraryManager = GetLibraryManager();

            var compilerOptionsProvider = new Mock <ICompilerOptionsProvider>();

            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
            .Returns(new CompilerOptions {
                Defines = new[] { "MY_CUSTOM_DEFINE" }
            });
            var mvcRazorHost = new Mock <IMvcRazorHost>();

            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
            .Returns("My");

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryManager,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost.Object,
                                                                  GetOptions());
            var relativeFileInfo = new RelativeFileInfo(new TestFileInfo {
                PhysicalPath = "SomePath"
            },
                                                        "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.NotNull(result.CompiledType);
            Assert.Equal("MyCustomDefinedClass", result.CompiledType.Name);
        }
Esempio n. 18
0
        public void GetOrAdd_IgnoresCachedValueIfFileIsIdentical_ButViewImportsWasAdedSinceTheCacheWasCreated()
        {
            // Arrange
            var expectedType    = typeof(RuntimeCompileDifferent);
            var fileProvider    = new TestFileProvider();
            var collection      = new ViewCollection();
            var precompiledFile = collection.FileInfos[0];

            precompiledFile.RelativePath = "Views\\home\\index.cshtml";
            var cache    = new CompilerCache(new[] { collection }, TestLoadContext, fileProvider);
            var testFile = new TestFileInfo
            {
                Content      = new PreCompile().Content,
                LastModified = precompiledFile.LastModified,
                PhysicalPath = precompiledFile.RelativePath
            };

            fileProvider.AddFile(precompiledFile.RelativePath, testFile);
            var relativeFile = new RelativeFileInfo(testFile, testFile.PhysicalPath);

            // Act 1
            var result1 = cache.GetOrAdd(testFile.PhysicalPath,
                                         compile: _ => { throw new Exception("should not be called"); });

            // Assert 1
            Assert.NotSame(CompilerCacheResult.FileNotFound, result1);
            var actual1 = result1.CompilationResult;

            Assert.NotNull(actual1);
            Assert.Equal(typeof(PreCompile), actual1.CompiledType);

            // Act 2
            var globalTrigger = fileProvider.GetTrigger("Views\\_ViewImports.cshtml");

            globalTrigger.IsExpired = true;
            var result2 = cache.GetOrAdd(testFile.PhysicalPath,
                                         compile: _ => CompilationResult.Successful(expectedType));

            // Assert 2
            Assert.NotSame(CompilerCacheResult.FileNotFound, result2);
            var actual2 = result2.CompilationResult;

            Assert.NotNull(actual2);
            Assert.Equal(expectedType, actual2.CompiledType);
        }
Esempio n. 19
0
        private GetOrAddResult OnCacheMiss(RelativeFileInfo file,
                                           string normalizedPath,
                                           Func <RelativeFileInfo, CompilationResult> compile)
        {
            var compilationResult = compile(file).EnsureSuccessful();

            // Concurrent addition to MemoryCache with the same key result in safe race.
            var compilerCacheEntry = new CompilerCacheEntry(file, compilationResult.CompiledType);
            var cacheEntry         = _cache.Set <CompilerCacheEntry>(
                normalizedPath,
                compilerCacheEntry,
                GetMemoryCacheEntryOptions(compilerCacheEntry.RelativePath));

            return(new GetOrAddResult
            {
                CompilationResult = compilationResult,
                CompilerCacheEntry = cacheEntry
            });
        }
Esempio n. 20
0
        public void Compile_ReturnsFailedResultIfParseFails()
        {
            // Arrange
            var errorSink = new ErrorSink();

            errorSink.OnError(new RazorError("some message", 1, 1, 1, 1));
            var generatorResult = new GeneratorResults(
                new Block(new BlockBuilder {
                Type = BlockType.Comment
            }),
                Enumerable.Empty <TagHelperDescriptor>(),
                errorSink,
                new CodeGeneratorResult("", new LineMapping[0]),
                new ChunkTree());
            var host = new Mock <IMvcRazorHost>();

            host.Setup(h => h.GenerateCode(It.IsAny <string>(), It.IsAny <Stream>()))
            .Returns(generatorResult)
            .Verifiable();

            var fileInfo = new Mock <IFileInfo>();

            fileInfo.Setup(f => f.CreateReadStream())
            .Returns(Stream.Null);

            var compiler         = new Mock <ICompilationService>(MockBehavior.Strict);
            var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");
            var razorService     = new RazorCompilationService(compiler.Object, host.Object, GetOptions());

            // Act
            var result = razorService.Compile(relativeFileInfo);

            // Assert
            Assert.NotNull(result.CompilationFailures);
            Assert.Collection(result.CompilationFailures,
                              failure =>
            {
                var message = Assert.Single(failure.Messages);
                Assert.Equal("some message", message.Message);
            });
            host.Verify();
        }
Esempio n. 21
0
        /// <inheritdoc />
        public CompilationResult Compile(RelativeFileInfo file)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            GeneratorResults results;
            using (var inputStream = file.FileInfo.CreateReadStream())
            {
                results = GenerateCode(file.RelativePath, inputStream);
            }

            if (!results.Success)
            {
                return GetCompilationFailedResult(file, results.ParserErrors);
            }

            return _compilationService.Compile(file, results.GeneratedCode);
        }
        public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
        {
            // Arrange
            var viewPath               = "some-relative-path";
            var fileContent            = "test file content";
            var content                = $@"
#line 1 ""{viewPath}""
this should fail";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor               = GetLoadContextAccessor();
            var libraryManager         = GetLibraryManager();

            var compilerOptionsProvider = new Mock <ICompilerOptionsProvider>();

            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
            .Returns(new CompilerOptions());
            var mvcRazorHost = Mock.Of <IMvcRazorHost>();
            var fileProvider = new TestFileProvider();
            var fileInfo     = fileProvider.AddFile(viewPath, fileContent);

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryManager,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost,
                                                                  GetOptions(fileProvider));
            var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType <CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);

            Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
            Assert.Equal(fileContent, compilationFailure.SourceFileContent);
        }
Esempio n. 23
0
        public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation()
        {
            // Arrange
            var content = @"
#if MY_CUSTOM_DEFINE
public class MyCustomDefinedClass {}
#else
public class MyNonCustomDefinedClass {}
#endif
";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter        = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost           = new Mock <IMvcRazorHost>();

            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
            .Returns("My");

            var options = GetOptions();

            options.Value.ParseOptions = options.Value.ParseOptions.WithPreprocessorSymbols("MY_CUSTOM_DEFINE");

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost.Object,
                options,
                GetFileProviderAccessor(),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(
                new TestFileInfo {
                PhysicalPath = "SomePath"
            },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.NotNull(result.CompiledType);
            Assert.Equal("MyCustomDefinedClass", result.CompiledType.Name);
        }
Esempio n. 24
0
        /// <inheritdoc />
        public CompilationResult Compile(RelativeFileInfo file)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            GeneratorResults results;

            using (var inputStream = file.FileInfo.CreateReadStream())
            {
                results = GenerateCode(file.RelativePath, inputStream);
            }

            if (!results.Success)
            {
                return(GetCompilationFailedResult(file, results.ParserErrors));
            }

            return(_compilationService.Compile(file, results.GeneratedCode));
        }
Esempio n. 25
0
        public void Compile_DoesNotThrow_IfFileCannotBeRead()
        {
            // Arrange
            var path    = "some-relative-path";
            var content = $@"
#line 1 ""{path}""
this should fail";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter        = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost           = Mock.Of <IMvcRazorHost>();

            var mockFileInfo = new Mock <IFileInfo>();

            mockFileInfo.Setup(f => f.CreateReadStream())
            .Throws(new Exception());
            var fileProvider = new TestFileProvider();

            fileProvider.AddFile(path, mockFileInfo.Object);

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost,
                GetOptions(),
                GetFileProviderAccessor(fileProvider),
                NullLoggerFactory.Instance);

            var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType <CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);

            Assert.Equal(path, compilationFailure.SourceFilePath);
            Assert.Null(compilationFailure.SourceFileContent);
        }
        public void Compile_ReturnsSingleTypeThatStartsWithMainClassNamePrefix()
        {
            // Arrange
            var content = @"
public class RazorPrefixType  {}
public class NotRazorPrefixType {}";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor       = GetLoadContextAccessor();
            var libraryManager = GetLibraryManager();

            var compilerOptionsProvider = new Mock <ICompilerOptionsProvider>();

            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
            .Returns(new CompilerOptions());
            var mvcRazorHost = new Mock <IMvcRazorHost>();

            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
            .Returns("RazorPrefix");

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryManager,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost.Object,
                                                                  GetOptions());

            var relativeFileInfo = new RelativeFileInfo(new TestFileInfo {
                PhysicalPath = "SomePath"
            },
                                                        "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.NotNull(result.CompiledType);
            Assert.Equal("RazorPrefixType", result.CompiledType.Name);
        }
        public void Compile_ReturnsUncachedCompilationResultWithCompiledContent()
        {
            // Arrange
            var content = @"
public class MyTestType  {}";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor       = GetLoadContextAccessor();
            var libraryManager = GetLibraryManager();

            var compilerOptionsProvider = new Mock <ICompilerOptionsProvider>();

            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
            .Returns(new CompilerOptions());
            var mvcRazorHost = new Mock <IMvcRazorHost>();

            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
            .Returns(string.Empty);

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryManager,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost.Object,
                                                                  GetOptions());
            var relativeFileInfo = new RelativeFileInfo(new TestFileInfo {
                PhysicalPath = "SomePath"
            },
                                                        "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            var uncachedResult = Assert.IsType <UncachedCompilationResult>(result);

            Assert.Equal("MyTestType", result.CompiledType.Name);
            Assert.Equal(content, uncachedResult.CompiledContent);
        }
        public void Compile_ReturnsGeneratedCodePath_IfLinePragmaIsNotAvailable()
        {
            // Arrange
            var fileContent            = "file content";
            var content                = @"this should fail";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor               = GetLoadContextAccessor();
            var libraryManager         = GetLibraryManager();

            var compilerOptionsProvider = new Mock <ICompilerOptionsProvider>();

            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
            .Returns(new CompilerOptions());
            var mvcRazorHost = Mock.Of <IMvcRazorHost>();

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryManager,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost,
                                                                  GetOptions());
            var relativeFileInfo = new RelativeFileInfo(new TestFileInfo {
                Content = fileContent
            },
                                                        "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType <CompilationResult>(result);
            Assert.Null(result.CompiledType);

            var compilationFailure = Assert.Single(result.CompilationFailures);

            Assert.Equal("Generated Code", compilationFailure.SourceFilePath);
            Assert.Equal(content, compilationFailure.SourceFileContent);
        }
        public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
        {
            // Arrange
            var viewPath = "some-relative-path";
            var fileContent = "test file content";
            var content = $@"
#line 1 ""{viewPath}""
this should fail";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor = GetLoadContextAccessor();
            var libraryExporter = GetLibraryExporter();

            var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
                                   .Returns(new CompilerOptions());
            var mvcRazorHost = Mock.Of<IMvcRazorHost>();
            var fileProvider = new TestFileProvider();
            var fileInfo = fileProvider.AddFile(viewPath, fileContent);

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryExporter,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost,
                                                                  GetOptions(fileProvider));
            var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
            Assert.Equal(fileContent, compilationFailure.SourceFileContent);
        }
Esempio n. 30
0
        /// <inheritdoc />
        public CompilerCacheResult GetOrAdd(
            [NotNull] string relativePath,
            [NotNull] Func <RelativeFileInfo, CompilationResult> compile)
        {
            var normalizedPath = NormalizePath(relativePath);
            CompilerCacheResult cacheResult;

            if (!_cache.TryGetValue(normalizedPath, out cacheResult))
            {
                var fileInfo = _fileProvider.GetFileInfo(relativePath);
                MemoryCacheEntryOptions cacheEntryOptions;
                CompilerCacheResult     cacheResultToCache;
                if (!fileInfo.Exists)
                {
                    cacheResultToCache = CompilerCacheResult.FileNotFound;
                    cacheResult        = CompilerCacheResult.FileNotFound;

                    cacheEntryOptions = new MemoryCacheEntryOptions();
                    cacheEntryOptions.AddExpirationTrigger(_fileProvider.Watch(relativePath));
                }
                else
                {
                    var relativeFileInfo  = new RelativeFileInfo(fileInfo, relativePath);
                    var compilationResult = compile(relativeFileInfo).EnsureSuccessful();
                    cacheEntryOptions = GetMemoryCacheEntryOptions(relativePath);

                    // By default the CompilationResult returned by IRoslynCompiler is an instance of
                    // UncachedCompilationResult. This type has the generated code as a string property and do not want
                    // to cache it. We'll instead cache the unwrapped result.
                    cacheResultToCache = new CompilerCacheResult(
                        CompilationResult.Successful(compilationResult.CompiledType));
                    cacheResult = new CompilerCacheResult(compilationResult);
                }

                _cache.Set(normalizedPath, cacheResultToCache, cacheEntryOptions);
            }

            return(cacheResult);
        }
Esempio n. 31
0
        public void Compile_ReturnsResultFromCompilationServiceIfParseSucceeds()
        {
            // Arrange
            var code            = "compiled-content";
            var generatorResult = new GeneratorResults(
                new Block(new BlockBuilder {
                Type = BlockType.Comment
            }),
                Enumerable.Empty <TagHelperDescriptor>(),
                new ErrorSink(),
                new CodeGeneratorResult(code, new LineMapping[0]),
                new ChunkTree());
            var host = new Mock <IMvcRazorHost>();

            host.Setup(h => h.GenerateCode(It.IsAny <string>(), It.IsAny <Stream>()))
            .Returns(generatorResult);

            var fileInfo = new Mock <IFileInfo>();

            fileInfo.Setup(f => f.CreateReadStream())
            .Returns(Stream.Null);
            var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");

            var compilationResult = CompilationResult.Successful(typeof(object));
            var compiler          = new Mock <ICompilationService>();

            compiler.Setup(c => c.Compile(relativeFileInfo, code))
            .Returns(compilationResult)
            .Verifiable();
            var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions());

            // Act
            var result = razorService.Compile(relativeFileInfo);

            // Assert
            Assert.Same(compilationResult, result);
            compiler.Verify();
        }
Esempio n. 32
0
        /// <inheritdoc />
        public CompilerCacheResult GetOrAdd(
            [NotNull] string relativePath,
            [NotNull] Func<RelativeFileInfo, CompilationResult> compile)
        {
            var normalizedPath = NormalizePath(relativePath);
            CompilerCacheResult cacheResult;
            if (!_cache.TryGetValue(normalizedPath, out cacheResult))
            {
                var fileInfo = _fileProvider.GetFileInfo(relativePath);
                MemoryCacheEntryOptions cacheEntryOptions;
                CompilerCacheResult cacheResultToCache;
                if (!fileInfo.Exists)
                {
                    cacheResultToCache = CompilerCacheResult.FileNotFound;
                    cacheResult = CompilerCacheResult.FileNotFound;

                    cacheEntryOptions = new MemoryCacheEntryOptions();
                    cacheEntryOptions.AddExpirationTrigger(_fileProvider.Watch(relativePath));
                }
                else
                {
                    var relativeFileInfo = new RelativeFileInfo(fileInfo, relativePath);
                    var compilationResult = compile(relativeFileInfo).EnsureSuccessful();
                    cacheEntryOptions = GetMemoryCacheEntryOptions(relativePath);

                    // By default the CompilationResult returned by IRoslynCompiler is an instance of
                    // UncachedCompilationResult. This type has the generated code as a string property and do not want
                    // to cache it. We'll instead cache the unwrapped result.
                    cacheResultToCache = new CompilerCacheResult(
                        CompilationResult.Successful(compilationResult.CompiledType));
                    cacheResult = new CompilerCacheResult(compilationResult);
                }

                _cache.Set(normalizedPath, cacheResultToCache, cacheEntryOptions);
            }

            return cacheResult;
        }
Esempio n. 33
0
        // Internal for unit testing
        internal CompilationResult GetCompilationFailedResult(RelativeFileInfo file, IEnumerable<RazorError> errors)
        {
            // If a SourceLocation does not specify a file path, assume it is produced
            // from parsing the current file.
            var messageGroups = errors
                .GroupBy(razorError =>
                razorError.Location.FilePath ?? file.RelativePath,
                StringComparer.Ordinal);

            var failures = new List<CompilationFailure>();
            foreach (var group in messageGroups)
            {
                var filePath = group.Key;
                var fileContent = ReadFileContentsSafely(filePath);
                var compilationFailure = new CompilationFailure(
                    filePath,
                    fileContent,
                    group.Select(parserError => CreateDiagnosticMessage(parserError, filePath)));
                failures.Add(compilationFailure);
            }

            return CompilationResult.Failed(failures);
        }
        public void Compile_ReturnsFailedResultIfParseFails()
        {
            // Arrange
            var errorSink = new ErrorSink();
            errorSink.OnError(new RazorError("some message", 1, 1, 1, 1));
            var generatorResult = new GeneratorResults(
                    new Block(new BlockBuilder { Type = BlockType.Comment }),
                    Enumerable.Empty<TagHelperDescriptor>(),
                    errorSink,
                    new CodeGeneratorResult("", new LineMapping[0]),
                    new ChunkTree());
            var host = new Mock<IMvcRazorHost>();
            host.Setup(h => h.GenerateCode(It.IsAny<string>(), It.IsAny<Stream>()))
                .Returns(generatorResult)
                .Verifiable();

            var fileInfo = new Mock<IFileInfo>();
            fileInfo.Setup(f => f.CreateReadStream())
                    .Returns(Stream.Null);

            var compiler = new Mock<ICompilationService>(MockBehavior.Strict);
            var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");
            var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions());

            // Act
            var result = razorService.Compile(relativeFileInfo);

            // Assert
            Assert.NotNull(result.CompilationFailures);
            Assert.Collection(result.CompilationFailures,
                failure =>
                {
                    var message = Assert.Single(failure.Messages);
                    Assert.Equal("some message", message.Message);
                });
            host.Verify();
        }
Esempio n. 35
0
        /// <inheritdoc />
        public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent)
        {
            if (fileInfo == null)
            {
                throw new ArgumentNullException(nameof(fileInfo));
            }

            if (compilationContent == null)
            {
                throw new ArgumentNullException(nameof(compilationContent));
            }

            var assemblyName = Path.GetRandomFileName();
            var compilationSettings = _compilerOptionsProvider.GetCompilationSettings(_environment);
            var syntaxTree = SyntaxTreeGenerator.Generate(
                compilationContent,
                assemblyName,
                compilationSettings);

            var references = _applicationReferences.Value;

            var compilationOptions = compilationSettings
                .CompilationOptions
                .WithOutputKind(OutputKind.DynamicallyLinkedLibrary);

            var compilation = CSharpCompilation.Create(
                assemblyName,
                options: compilationOptions,
                syntaxTrees: new[] { syntaxTree },
                references: references);

            compilation = Rewrite(compilation);

            using (var ms = new MemoryStream())
            {
                using (var pdb = new MemoryStream())
                {
                    EmitResult result;

                    if (_supportsPdbGeneration.Value)
                    {
                        result = compilation.Emit(ms, pdbStream: pdb);
                    }
                    else
                    {
                        result = compilation.Emit(ms);
                    }

                    if (!result.Success)
                    {
                        return GetCompilationFailedResult(
                            fileInfo.RelativePath,
                            compilationContent,
                            assemblyName,
                            result.Diagnostics);
                    }

                    Assembly assembly;
                    ms.Seek(0, SeekOrigin.Begin);

                    if (_supportsPdbGeneration.Value)
                    {
                        pdb.Seek(0, SeekOrigin.Begin);
                        assembly = LoadStream(ms, pdb);
                    }
                    else
                    {
                        assembly = LoadStream(ms, assemblySymbols: null);
                    }

                    var type = assembly.GetExportedTypes()
                                       .First(t => t.Name.StartsWith(_classPrefix, StringComparison.Ordinal));

                    return UncachedCompilationResult.Successful(type, compilationContent);
                }
            }
        }
Esempio n. 36
0
        private GetOrAddResult OnCacheMiss(RelativeFileInfo file,
                                           string normalizedPath,
                                           Func<RelativeFileInfo, CompilationResult> compile)
        {
            var compilationResult = compile(file).EnsureSuccessful();

            // Concurrent addition to MemoryCache with the same key result in safe race.
            var compilerCacheEntry = new CompilerCacheEntry(file, compilationResult.CompiledType);
            var cacheEntry = _cache.Set<CompilerCacheEntry>(
                normalizedPath,
                compilerCacheEntry,
                GetMemoryCacheEntryOptions(compilerCacheEntry.RelativePath));

            return new GetOrAddResult
            {
                CompilationResult = compilationResult,
                CompilerCacheEntry = cacheEntry
            };
        }
        public void Compile_DoesNotThrow_IfFileCannotBeRead()
        {
            // Arrange
            var path = "some-relative-path";
            var content = $@"
#line 1 ""{path}""
this should fail";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost = Mock.Of<IMvcRazorHost>();

            var mockFileInfo = new Mock<IFileInfo>();
            mockFileInfo.Setup(f => f.CreateReadStream())
                .Throws(new Exception());
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(path, mockFileInfo.Object);

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost,
                GetOptions(),
                GetFileProviderAccessor(fileProvider),
                NullLoggerFactory.Instance);

            var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal(path, compilationFailure.SourceFilePath);
            Assert.Null(compilationFailure.SourceFileContent);
        }
Esempio n. 38
0
        public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages()
        {
            // Arrange
            var viewPath        = @"views/index.razor";
            var viewImportsPath = @"views/global.import.cshtml";
            var host            = Mock.Of <IMvcRazorHost>();

            var fileProvider = new TestFileProvider();
            var file         = fileProvider.AddFile(viewPath, "View Content");

            fileProvider.AddFile(viewImportsPath, "Global Import Content");
            var relativeFileInfo = new RelativeFileInfo(file, viewPath);
            var razorService     = new RazorCompilationService(
                Mock.Of <ICompilationService>(),
                Mock.Of <IMvcRazorHost>(),
                GetOptions(fileProvider));
            var errors = new[]
            {
                new RazorError("message-1", new SourceLocation(1, 2, 17), length: 1),
                new RazorError("message-2", new SourceLocation(viewPath, 1, 4, 6), 7),
                new RazorError {
                    Message = "message-3"
                },
                new RazorError("message-4", new SourceLocation(viewImportsPath, 1, 3, 8), 4),
            };

            // Act
            var result = razorService.GetCompilationFailedResult(relativeFileInfo, errors);

            // Assert
            Assert.NotNull(result.CompilationFailures);
            Assert.Collection(result.CompilationFailures,
                              failure =>
            {
                Assert.Equal(viewPath, failure.SourceFilePath);
                Assert.Equal("View Content", failure.SourceFileContent);
                Assert.Collection(failure.Messages,
                                  message =>
                {
                    Assert.Equal(errors[0].Message, message.Message);
                    Assert.Equal(viewPath, message.SourceFilePath);
                    Assert.Equal(3, message.StartLine);
                    Assert.Equal(17, message.StartColumn);
                    Assert.Equal(3, message.EndLine);
                    Assert.Equal(18, message.EndColumn);
                },
                                  message =>
                {
                    Assert.Equal(errors[1].Message, message.Message);
                    Assert.Equal(viewPath, message.SourceFilePath);
                    Assert.Equal(5, message.StartLine);
                    Assert.Equal(6, message.StartColumn);
                    Assert.Equal(5, message.EndLine);
                    Assert.Equal(13, message.EndColumn);
                },
                                  message =>
                {
                    Assert.Equal(errors[2].Message, message.Message);
                    Assert.Equal(viewPath, message.SourceFilePath);
                    Assert.Equal(0, message.StartLine);
                    Assert.Equal(-1, message.StartColumn);
                    Assert.Equal(0, message.EndLine);
                    Assert.Equal(-2, message.EndColumn);
                });
            },
                              failure =>
            {
                Assert.Equal(viewImportsPath, failure.SourceFilePath);
                Assert.Equal("Global Import Content", failure.SourceFileContent);
                Assert.Collection(failure.Messages,
                                  message =>
                {
                    Assert.Equal(errors[3].Message, message.Message);
                    Assert.Equal(viewImportsPath, message.SourceFilePath);
                    Assert.Equal(4, message.StartLine);
                    Assert.Equal(8, message.StartColumn);
                    Assert.Equal(4, message.EndLine);
                    Assert.Equal(12, message.EndColumn);
                });
            });
        }
        public void Compile_RunsCallback()
        {
            var content = "public class MyTestType  {}";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter = CompilationServices.Default.LibraryExporter;
            RoslynCompilationContext usedCompilation = null;
            var mvcRazorHost = new Mock<IMvcRazorHost>();
            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
                        .Returns(string.Empty);

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost.Object,
                GetOptions(callback: c => usedCompilation = c),
                GetFileProviderAccessor(),
                NullLoggerFactory.Instance);

            var relativeFileInfo = new RelativeFileInfo(
                new TestFileInfo { PhysicalPath = "SomePath" },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            Assert.NotNull(usedCompilation);
            Assert.NotNull(usedCompilation.Compilation);
            Assert.Equal(1, usedCompilation.Compilation.SyntaxTrees.Length);
        }
Esempio n. 40
0
 private CompilationResult ThrowsIfCalled(RelativeFileInfo file)
 {
     throw new Exception("Shouldn't be called");
 }
        public void Compile_DoesNotThrow_IfFileCannotBeRead()
        {
            // Arrange
            var path = "some-relative-path";
            var content = $@"
#line 1 ""{path}""
this should fail";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor = GetLoadContextAccessor();
            var libraryExporter = GetLibraryExporter();

            var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
                                   .Returns(new CompilerOptions());
            var mvcRazorHost = Mock.Of<IMvcRazorHost>();

            var mockFileInfo = new Mock<IFileInfo>();
            mockFileInfo.Setup(f => f.CreateReadStream())
                        .Throws(new Exception());
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(path, mockFileInfo.Object);

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryExporter,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost,
                                                                  GetOptions(fileProvider));
            
            var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal(path, compilationFailure.SourceFilePath);
            Assert.Null(compilationFailure.SourceFileContent);
        }
        public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation()
        {
            // Arrange
            var content = @"
#if MY_CUSTOM_DEFINE
public class MyCustomDefinedClass {}
#else
public class MyNonCustomDefinedClass {}
#endif
";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor = GetLoadContextAccessor();
            var libraryExporter = GetLibraryExporter();

            var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
                                   .Returns(new CompilerOptions { Defines = new[] { "MY_CUSTOM_DEFINE" } });
            var mvcRazorHost = new Mock<IMvcRazorHost>();
            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
                        .Returns("My");

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryExporter,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost.Object,
                                                                  GetOptions());
            var relativeFileInfo = new RelativeFileInfo(new TestFileInfo { PhysicalPath = "SomePath" },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.NotNull(result.CompiledType);
            Assert.Equal("MyCustomDefinedClass", result.CompiledType.Name);
        }
        public void Compile_ReturnsSingleTypeThatStartsWithMainClassNamePrefix()
        {
            // Arrange
            var content = @"
public class RazorPrefixType  {}
public class NotRazorPrefixType {}";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor = GetLoadContextAccessor();
            var libraryExporter = GetLibraryExporter();

            var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
                                   .Returns(new CompilerOptions());
            var mvcRazorHost = new Mock<IMvcRazorHost>();
            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
                        .Returns("RazorPrefix");

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryExporter,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost.Object,
                                                                  GetOptions());

            var relativeFileInfo = new RelativeFileInfo(new TestFileInfo { PhysicalPath = "SomePath" },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.NotNull(result.CompiledType);
            Assert.Equal("RazorPrefixType", result.CompiledType.Name);
        }
        public void Compile_ReturnsGeneratedCodePath_IfLinePragmaIsNotAvailable()
        {
            // Arrange
            var fileContent = "file content";
            var content = @"this should fail";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor = GetLoadContextAccessor();
            var libraryExporter = GetLibraryExporter();

            var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
                                   .Returns(new CompilerOptions());
            var mvcRazorHost = Mock.Of<IMvcRazorHost>();

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryExporter,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost,
                                                                  GetOptions());
            var relativeFileInfo = new RelativeFileInfo(new TestFileInfo { Content = fileContent },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);

            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal("Generated Code", compilationFailure.SourceFilePath);
            Assert.Equal(content, compilationFailure.SourceFileContent);
        }
Esempio n. 45
0
        /// <inheritdoc />
        public CompilationResult Compile([NotNull] RelativeFileInfo fileInfo, [NotNull] string compilationContent)
        {
            var assemblyName        = Path.GetRandomFileName();
            var compilationSettings = _compilerOptionsProvider.GetCompilationSettings(_environment);
            var syntaxTree          = SyntaxTreeGenerator.Generate(compilationContent,
                                                                   assemblyName,
                                                                   compilationSettings);
            var references = _applicationReferences.Value;

            var compilationOptions = compilationSettings.CompilationOptions
                                     .WithOutputKind(OutputKind.DynamicallyLinkedLibrary);

            var compilation = CSharpCompilation.Create(assemblyName,
                                                       options: compilationOptions,
                                                       syntaxTrees: new[] { syntaxTree },
                                                       references: references);

            using (var ms = new MemoryStream())
            {
                using (var pdb = new MemoryStream())
                {
                    EmitResult result;

                    if (_supportsPdbGeneration.Value)
                    {
                        result = compilation.Emit(ms, pdbStream: pdb);
                    }
                    else
                    {
                        result = compilation.Emit(ms);
                    }

                    if (!result.Success)
                    {
                        return(GetCompilationFailedResult(
                                   fileInfo.RelativePath,
                                   compilationContent,
                                   assemblyName,
                                   result.Diagnostics));
                    }

                    Assembly assembly;
                    ms.Seek(0, SeekOrigin.Begin);

                    if (_supportsPdbGeneration.Value)
                    {
                        pdb.Seek(0, SeekOrigin.Begin);
                        assembly = _loader.LoadStream(ms, pdb);
                    }
                    else
                    {
                        assembly = _loader.LoadStream(ms, assemblySymbols: null);
                    }

                    var type = assembly.GetExportedTypes()
                               .First(t => t.Name.StartsWith(_classPrefix, StringComparison.Ordinal));

                    return(UncachedCompilationResult.Successful(type, compilationContent));
                }
            }
        }
Esempio n. 46
0
        private GetOrAddResult GetOrAddCore(string relativePath,
                                            Func <RelativeFileInfo, CompilationResult> compile)
        {
            var normalizedPath = NormalizePath(relativePath);
            var cacheEntry     = _cache.Get <CompilerCacheEntry>(normalizedPath);

            if (cacheEntry == null)
            {
                var fileInfo = _fileProvider.GetFileInfo(relativePath);
                if (!fileInfo.Exists)
                {
                    return(null);
                }

                var relativeFileInfo = new RelativeFileInfo(fileInfo, relativePath);
                return(OnCacheMiss(relativeFileInfo, normalizedPath, compile));
            }
            else if (cacheEntry.IsPreCompiled && !cacheEntry.IsValidatedPreCompiled)
            {
                // For precompiled views, the first time the entry is read, we need to ensure that no changes were made
                // either to the file associated with this entry, or any _ViewImports associated with it between the time
                // the View was precompiled and the time EnsureInitialized was called. For later iterations, we can
                // rely on expiration triggers ensuring the validity of the entry.

                var fileInfo = _fileProvider.GetFileInfo(relativePath);
                if (!fileInfo.Exists)
                {
                    return(null);
                }

                var relativeFileInfo = new RelativeFileInfo(fileInfo, relativePath);
                if (cacheEntry.Length != fileInfo.Length)
                {
                    // Recompile if the file lengths differ
                    return(OnCacheMiss(relativeFileInfo, normalizedPath, compile));
                }

                if (AssociatedGlobalFilesChanged(cacheEntry, compile))
                {
                    // Recompile if _ViewImports have changed since the entry was created.
                    return(OnCacheMiss(relativeFileInfo, normalizedPath, compile));
                }

                if (cacheEntry.LastModified == fileInfo.LastModified)
                {
                    // Assigning to IsValidatedPreCompiled is an atomic operation and will result in a safe race
                    // if it is being concurrently updated and read.
                    cacheEntry.IsValidatedPreCompiled = true;
                    return(new GetOrAddResult
                    {
                        CompilationResult = CompilationResult.Successful(cacheEntry.CompiledType),
                        CompilerCacheEntry = cacheEntry
                    });
                }

                // Timestamp doesn't match but it might be because of deployment, compare the hash.
                if (cacheEntry.IsPreCompiled &&
                    string.Equals(cacheEntry.Hash,
                                  RazorFileHash.GetHash(fileInfo, cacheEntry.HashAlgorithmVersion),
                                  StringComparison.Ordinal))
                {
                    // Cache hit, but we need to update the entry.
                    // Assigning to LastModified and IsValidatedPreCompiled are atomic operations and will result in safe race
                    // if the entry is being concurrently read or updated.
                    cacheEntry.LastModified           = fileInfo.LastModified;
                    cacheEntry.IsValidatedPreCompiled = true;
                    return(new GetOrAddResult
                    {
                        CompilationResult = CompilationResult.Successful(cacheEntry.CompiledType),
                        CompilerCacheEntry = cacheEntry
                    });
                }

                // it's not a match, recompile
                return(OnCacheMiss(relativeFileInfo, normalizedPath, compile));
            }

            return(new GetOrAddResult
            {
                CompilationResult = CompilationResult.Successful(cacheEntry.CompiledType),
                CompilerCacheEntry = cacheEntry
            });
        }
Esempio n. 47
0
        private CompilerCacheResult CreateCacheEntry(
            string normalizedPath,
            Func<RelativeFileInfo, CompilationResult> compile)
        {
            CompilerCacheResult cacheResult;
            var fileInfo = _fileProvider.GetFileInfo(normalizedPath);
            MemoryCacheEntryOptions cacheEntryOptions;
            CompilerCacheResult cacheResultToCache;
            if (!fileInfo.Exists)
            {
                cacheResultToCache = CompilerCacheResult.FileNotFound;
                cacheResult = CompilerCacheResult.FileNotFound;

                cacheEntryOptions = new MemoryCacheEntryOptions();
                cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(normalizedPath));
            }
            else
            {
                var relativeFileInfo = new RelativeFileInfo(fileInfo, normalizedPath);
                var compilationResult = compile(relativeFileInfo).EnsureSuccessful();
                cacheEntryOptions = GetMemoryCacheEntryOptions(normalizedPath);

                // By default the CompilationResult returned by IRoslynCompiler is an instance of
                // UncachedCompilationResult. This type has the generated code as a string property and do not want
                // to cache it. We'll instead cache the unwrapped result.
                cacheResultToCache = new CompilerCacheResult(
                    CompilationResult.Successful(compilationResult.CompiledType));
                cacheResult = new CompilerCacheResult(compilationResult);
            }

            _cache.Set(normalizedPath, cacheResultToCache, cacheEntryOptions);
            return cacheResult;
        }
Esempio n. 48
0
        /// <inheritdoc />
        public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent)
        {
            if (fileInfo == null)
            {
                throw new ArgumentNullException(nameof(fileInfo));
            }

            if (compilationContent == null)
            {
                throw new ArgumentNullException(nameof(compilationContent));
            }

            _logger.GeneratedCodeToAssemblyCompilationStart(fileInfo.RelativePath);

            var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;

            var assemblyName = Path.GetRandomFileName();

            var syntaxTree = SyntaxTreeGenerator.Generate(
                compilationContent,
                assemblyName,
                _parseOptions);

            var references = _applicationReferences.Value;

            var compilation = CSharpCompilation.Create(
                assemblyName,
                options: _compilationOptions,
                syntaxTrees: new[] { syntaxTree },
                references: references);

            compilation = Rewrite(compilation);

            var compilationContext = new RoslynCompilationContext(compilation);

            _compilationCallback(compilationContext);
            compilation = compilationContext.Compilation;

            using (var ms = new MemoryStream())
            {
                using (var pdb = new MemoryStream())
                {
                    EmitResult result;

                    if (_supportsPdbGeneration.Value)
                    {
                        result = compilation.Emit(ms, pdbStream: pdb);
                    }
                    else
                    {
                        result = compilation.Emit(ms);
                    }

                    if (!result.Success)
                    {
                        return(GetCompilationFailedResult(
                                   fileInfo.RelativePath,
                                   compilationContent,
                                   assemblyName,
                                   result.Diagnostics));
                    }

                    Assembly assembly;
                    ms.Seek(0, SeekOrigin.Begin);

                    if (_supportsPdbGeneration.Value)
                    {
                        pdb.Seek(0, SeekOrigin.Begin);
                        assembly = LoadStream(ms, pdb);
                    }
                    else
                    {
                        assembly = LoadStream(ms, assemblySymbols: null);
                    }

                    var type = assembly.GetExportedTypes()
                               .First(t => t.Name.StartsWith(_classPrefix, StringComparison.Ordinal));

                    _logger.GeneratedCodeToAssemblyCompilationEnd(fileInfo.RelativePath, startTimestamp);

                    return(new CompilationResult(type));
                }
            }
        }
        /// <inheritdoc />
        public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent)
        {
            if (fileInfo == null)
            {
                throw new ArgumentNullException(nameof(fileInfo));
            }

            if (compilationContent == null)
            {
                throw new ArgumentNullException(nameof(compilationContent));
            }

            _logger.GeneratedCodeToAssemblyCompilationStart(fileInfo.RelativePath);

            var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;

            var assemblyName = Path.GetRandomFileName();

            var syntaxTree = SyntaxTreeGenerator.Generate(
                compilationContent,
                assemblyName,
                _parseOptions);

            var references = _applicationReferences.Value;

            var compilation = CSharpCompilation.Create(
                assemblyName,
                options: _compilationOptions,
                syntaxTrees: new[] { syntaxTree },
                references: references);

            compilation = Rewrite(compilation);

            var compilationContext = new RoslynCompilationContext(compilation);
            _compilationCallback(compilationContext);
            compilation = compilationContext.Compilation;

            using (var ms = new MemoryStream())
            {
                using (var pdb = new MemoryStream())
                {
                    EmitResult result;

                    if (_supportsPdbGeneration.Value)
                    {
                        result = compilation.Emit(ms, pdbStream: pdb);
                    }
                    else
                    {
                        result = compilation.Emit(ms);
                    }

                    if (!result.Success)
                    {
                        return GetCompilationFailedResult(
                            fileInfo.RelativePath,
                            compilationContent,
                            assemblyName,
                            result.Diagnostics);
                    }

                    Assembly assembly;
                    ms.Seek(0, SeekOrigin.Begin);

                    if (_supportsPdbGeneration.Value)
                    {
                        pdb.Seek(0, SeekOrigin.Begin);
                        assembly = LoadStream(ms, pdb);
                    }
                    else
                    {
                        assembly = LoadStream(ms, assemblySymbols: null);
                    }

                    var type = assembly.GetExportedTypes()
                                       .First(t => t.Name.StartsWith(_classPrefix, StringComparison.Ordinal));

                    _logger.GeneratedCodeToAssemblyCompilationEnd(fileInfo.RelativePath, startTimestamp);

                    return new CompilationResult(type);
                }
            }
        }
        public void Compile_ReturnsGeneratedCodePath_IfLinePragmaIsNotAvailable()
        {
            // Arrange
            var fileContent = "file content";
            var content = @"this should fail";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost = Mock.Of<IMvcRazorHost>();

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost,
                GetOptions(),
                GetFileProviderAccessor(),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(
                new TestFileInfo { Content = fileContent },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);

            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal("Generated Code", compilationFailure.SourceFilePath);
            Assert.Equal(content, compilationFailure.SourceFileContent);
        }
Esempio n. 51
0
        private Task <CompilerCacheResult> CreateCacheEntry(
            string normalizedPath,
            Func <RelativeFileInfo, CompilationResult> compile)
        {
            TaskCompletionSource <CompilerCacheResult> compilationTaskSource = null;
            MemoryCacheEntryOptions cacheEntryOptions = null;
            IFileInfo fileInfo = null;
            Task <CompilerCacheResult> cacheEntry;

            // Safe races cannot be allowed when compiling Razor pages. To ensure only one compilation request succeeds
            // per file, we'll lock the creation of a cache entry. Creating the cache entry should be very quick. The
            // actual work for compiling files happens outside the critical section.
            lock (_cacheLock)
            {
                if (_cache.TryGetValue(normalizedPath, out cacheEntry))
                {
                    return(cacheEntry);
                }

                fileInfo = _fileProvider.GetFileInfo(normalizedPath);
                if (!fileInfo.Exists)
                {
                    var expirationToken = _fileProvider.Watch(normalizedPath);
                    cacheEntry = Task.FromResult(new CompilerCacheResult(new[] { expirationToken }));

                    cacheEntryOptions = new MemoryCacheEntryOptions();
                    cacheEntryOptions.AddExpirationToken(expirationToken);
                }
                else
                {
                    cacheEntryOptions = GetMemoryCacheEntryOptions(normalizedPath);

                    // A file exists and needs to be compiled.
                    compilationTaskSource = new TaskCompletionSource <CompilerCacheResult>();
                    cacheEntry            = compilationTaskSource.Task;
                }

                cacheEntry = _cache.Set <Task <CompilerCacheResult> >(normalizedPath, cacheEntry, cacheEntryOptions);
            }

            if (compilationTaskSource != null)
            {
                // Indicates that the file was found and needs to be compiled.
                Debug.Assert(fileInfo != null && fileInfo.Exists);
                Debug.Assert(cacheEntryOptions != null);
                var relativeFileInfo = new RelativeFileInfo(fileInfo, normalizedPath);

                try
                {
                    var compilationResult = compile(relativeFileInfo);
                    compilationResult.EnsureSuccessful();
                    compilationTaskSource.SetResult(
                        new CompilerCacheResult(compilationResult, cacheEntryOptions.ExpirationTokens));
                }
                catch (Exception ex)
                {
                    compilationTaskSource.SetException(ex);
                }
            }

            return(cacheEntry);
        }
Esempio n. 52
0
 private CompilationResult ThrowsIfCalled(RelativeFileInfo file)
 {
     throw new Exception("Shouldn't be called");
 }
Esempio n. 53
0
        private Task<CompilerCacheResult> CreateCacheEntry(
            string normalizedPath,
            Func<RelativeFileInfo, CompilationResult> compile)
        {
            TaskCompletionSource<CompilerCacheResult> compilationTaskSource = null;
            MemoryCacheEntryOptions cacheEntryOptions = null;
            IFileInfo fileInfo = null;
            Task<CompilerCacheResult> cacheEntry;

            // Safe races cannot be allowed when compiling Razor pages. To ensure only one compilation request succeeds
            // per file, we'll lock the creation of a cache entry. Creating the cache entry should be very quick. The
            // actual work for compiling files happens outside the critical section.
            lock (_cacheLock)
            {
                if (_cache.TryGetValue(normalizedPath, out cacheEntry))
                {
                    return cacheEntry;
                }

                fileInfo = _fileProvider.GetFileInfo(normalizedPath);
                if (!fileInfo.Exists)
                {
                    var expirationToken = _fileProvider.Watch(normalizedPath);
                    cacheEntry = Task.FromResult(new CompilerCacheResult(new[] { expirationToken }));

                    cacheEntryOptions = new MemoryCacheEntryOptions();
                    cacheEntryOptions.AddExpirationToken(expirationToken);
                }
                else
                {
                    cacheEntryOptions = GetMemoryCacheEntryOptions(normalizedPath);

                    // A file exists and needs to be compiled.
                    compilationTaskSource = new TaskCompletionSource<CompilerCacheResult>();
                    cacheEntry = compilationTaskSource.Task;
                }

                cacheEntry = _cache.Set<Task<CompilerCacheResult>>(normalizedPath, cacheEntry, cacheEntryOptions);
            }

            if (compilationTaskSource != null)
            {
                // Indicates that the file was found and needs to be compiled.
                Debug.Assert(fileInfo != null && fileInfo.Exists);
                Debug.Assert(cacheEntryOptions != null);
                var relativeFileInfo = new RelativeFileInfo(fileInfo, normalizedPath);

                try
                {
                    var compilationResult = compile(relativeFileInfo);
                    compilationResult.EnsureSuccessful();
                    compilationTaskSource.SetResult(
                        new CompilerCacheResult(compilationResult, cacheEntryOptions.ExpirationTokens));
                }
                catch (Exception ex)
                {
                    compilationTaskSource.SetException(ex);
                }
            }

            return cacheEntry;
        }
        public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation()
        {
            // Arrange
            var content = @"
#if MY_CUSTOM_DEFINE
public class MyCustomDefinedClass {}
#else
public class MyNonCustomDefinedClass {}
#endif
";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost = new Mock<IMvcRazorHost>();
            mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
                .Returns("My");

            var options = GetOptions();
            options.Value.ParseOptions = options.Value.ParseOptions.WithPreprocessorSymbols("MY_CUSTOM_DEFINE");

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost.Object,
                options,
                GetFileProviderAccessor(),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(
                new TestFileInfo { PhysicalPath = "SomePath" },
                "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.NotNull(result.CompiledType);
            Assert.Equal("MyCustomDefinedClass", result.CompiledType.Name);
        }
Esempio n. 55
0
        private GetOrAddResult GetOrAddCore(string relativePath,
                                            Func<RelativeFileInfo, CompilationResult> compile)
        {
            var normalizedPath = NormalizePath(relativePath);
            var cacheEntry = _cache.Get<CompilerCacheEntry>(normalizedPath);
            if (cacheEntry == null)
            {
                var fileInfo = _fileProvider.GetFileInfo(relativePath);
                if (!fileInfo.Exists)
                {
                    return null;
                }

                var relativeFileInfo = new RelativeFileInfo(fileInfo, relativePath);
                return OnCacheMiss(relativeFileInfo, normalizedPath, compile);
            }
            else if (cacheEntry.IsPreCompiled && !cacheEntry.IsValidatedPreCompiled)
            {
                // For precompiled views, the first time the entry is read, we need to ensure that no changes were made
                // either to the file associated with this entry, or any _ViewImports associated with it between the time
                // the View was precompiled and the time EnsureInitialized was called. For later iterations, we can
                // rely on expiration triggers ensuring the validity of the entry.

                var fileInfo = _fileProvider.GetFileInfo(relativePath);
                if (!fileInfo.Exists)
                {
                    return null;
                }

                var relativeFileInfo = new RelativeFileInfo(fileInfo, relativePath);
                if (cacheEntry.Length != fileInfo.Length)
                {
                    // Recompile if the file lengths differ
                    return OnCacheMiss(relativeFileInfo, normalizedPath, compile);
                }

                if (AssociatedGlobalFilesChanged(cacheEntry, compile))
                {
                    // Recompile if _ViewImports have changed since the entry was created.
                    return OnCacheMiss(relativeFileInfo, normalizedPath, compile);
                }

                if (cacheEntry.LastModified == fileInfo.LastModified)
                {
                    // Assigning to IsValidatedPreCompiled is an atomic operation and will result in a safe race
                    // if it is being concurrently updated and read.
                    cacheEntry.IsValidatedPreCompiled = true;
                    return new GetOrAddResult
                    {
                        CompilationResult = CompilationResult.Successful(cacheEntry.CompiledType),
                        CompilerCacheEntry = cacheEntry
                    };
                }

                // Timestamp doesn't match but it might be because of deployment, compare the hash.
                if (cacheEntry.IsPreCompiled &&
                    string.Equals(cacheEntry.Hash,
                                  RazorFileHash.GetHash(fileInfo, cacheEntry.HashAlgorithmVersion),
                                  StringComparison.Ordinal))
                {
                    // Cache hit, but we need to update the entry.
                    // Assigning to LastModified and IsValidatedPreCompiled are atomic operations and will result in safe race
                    // if the entry is being concurrently read or updated.
                    cacheEntry.LastModified = fileInfo.LastModified;
                    cacheEntry.IsValidatedPreCompiled = true;
                    return new GetOrAddResult
                    {
                        CompilationResult = CompilationResult.Successful(cacheEntry.CompiledType),
                        CompilerCacheEntry = cacheEntry
                    };
                }

                // it's not a match, recompile
                return OnCacheMiss(relativeFileInfo, normalizedPath, compile);
            }

            return new GetOrAddResult
            {
                CompilationResult = CompilationResult.Successful(cacheEntry.CompiledType),
                CompilerCacheEntry = cacheEntry
            };
        }
        public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages()
        {
            // Arrange
            var viewPath = @"views/index.razor";
            var viewImportsPath = @"views/global.import.cshtml";
            var host = Mock.Of<IMvcRazorHost>();

            var fileProvider = new TestFileProvider();
            var file = fileProvider.AddFile(viewPath, "View Content");
            fileProvider.AddFile(viewImportsPath, "Global Import Content");
            var relativeFileInfo = new RelativeFileInfo(file, viewPath);
            var razorService = new RazorCompilationService(
                Mock.Of<ICompilationService>(),
                Mock.Of<IMvcRazorHost>(),
                GetOptions(fileProvider));
            var errors = new[]
            {
                new RazorError("message-1", new SourceLocation(1, 2, 17)),
                new RazorError("message-2", new SourceLocation(viewPath, 1, 4, 6), 7),
                new RazorError { Message = "message-3" },
                new RazorError("message-4", new SourceLocation(viewImportsPath, 1, 3, 8), 4),
            };

            // Act
            var result = razorService.GetCompilationFailedResult(relativeFileInfo, errors);

            // Assert
            Assert.NotNull(result.CompilationFailures);
            Assert.Collection(result.CompilationFailures,
                failure =>
                {
                    Assert.Equal(viewPath, failure.SourceFilePath);
                    Assert.Equal("View Content", failure.SourceFileContent);
                    Assert.Collection(failure.Messages,
                        message =>
                        {
                            Assert.Equal(errors[0].Message, message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(3, message.StartLine);
                            Assert.Equal(17, message.StartColumn);
                            Assert.Equal(3, message.EndLine);
                            Assert.Equal(18, message.EndColumn);
                        },
                        message =>
                        {
                            Assert.Equal(errors[1].Message, message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(5, message.StartLine);
                            Assert.Equal(6, message.StartColumn);
                            Assert.Equal(5, message.EndLine);
                            Assert.Equal(13, message.EndColumn);
                        },
                        message =>
                        {
                            Assert.Equal(errors[2].Message, message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(0, message.StartLine);
                            Assert.Equal(-1, message.StartColumn);
                            Assert.Equal(0, message.EndLine);
                            Assert.Equal(0, message.EndColumn);
                        });
                },
                failure =>
                {
                    Assert.Equal(viewImportsPath, failure.SourceFilePath);
                    Assert.Equal("Global Import Content", failure.SourceFileContent);
                    Assert.Collection(failure.Messages,
                        message =>
                        {
                            Assert.Equal(errors[3].Message, message.Message);
                            Assert.Equal(viewImportsPath, message.SourceFilePath);
                            Assert.Equal(4, message.StartLine);
                            Assert.Equal(8, message.StartColumn);
                            Assert.Equal(4, message.EndLine);
                            Assert.Equal(12, message.EndColumn);
                        });
                });
        }
        public void Compile_ReturnsResultFromCompilationServiceIfParseSucceeds()
        {
            // Arrange
            var code = "compiled-content";
            var generatorResult = new GeneratorResults(
                    new Block(new BlockBuilder { Type = BlockType.Comment }),
                    Enumerable.Empty<TagHelperDescriptor>(),
                    new ErrorSink(),
                    new CodeGeneratorResult(code, new LineMapping[0]),
                    new ChunkTree());
            var host = new Mock<IMvcRazorHost>();
            host.Setup(h => h.GenerateCode(It.IsAny<string>(), It.IsAny<Stream>()))
                .Returns(generatorResult);

            var fileInfo = new Mock<IFileInfo>();
            fileInfo.Setup(f => f.CreateReadStream())
                    .Returns(Stream.Null);
            var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");

            var compilationResult = CompilationResult.Successful(typeof(object));
            var compiler = new Mock<ICompilationService>();
            compiler.Setup(c => c.Compile(relativeFileInfo, code))
                    .Returns(compilationResult)
                    .Verifiable();
            var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions());

            // Act
            var result = razorService.Compile(relativeFileInfo);

            // Assert
            Assert.Same(compilationResult, result);
            compiler.Verify();
        }