diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/NamespaceDirective.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/NamespaceDirective.cs index 188b60f6ca..946788eb77 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/NamespaceDirective.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/NamespaceDirective.cs @@ -85,7 +85,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { var directiveSource = NormalizeDirectory(directive.Source?.FilePath); - var baseNamespace = directive.Tokens.First().Content; + var baseNamespace = directive.Tokens.FirstOrDefault()?.Content; + if (string.IsNullOrEmpty(baseNamespace)) + { + // The namespace directive was incomplete. + @namespace = string.Empty; + return false; + } + if (string.IsNullOrEmpty(source) || directiveSource == null) { // No sources, can't compute a suffix. diff --git a/src/Microsoft.AspNetCore.Razor.Language/RazorTemplateEngine.cs b/src/Microsoft.AspNetCore.Razor.Language/RazorTemplateEngine.cs index 62bee58376..5717db117d 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/RazorTemplateEngine.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/RazorTemplateEngine.cs @@ -182,12 +182,6 @@ namespace Microsoft.AspNetCore.Razor.Language { throw new ArgumentNullException(nameof(projectItem)); } - - if (!projectItem.Exists) - { - throw new InvalidOperationException(Resources.FormatRazorTemplateEngine_ItemCouldNotBeFound(projectItem.Path)); - } - var result = new List(); diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/NamespaceDirectiveTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/NamespaceDirectiveTest.cs index 292afbd945..688517e8cb 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/NamespaceDirectiveTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/NamespaceDirectiveTest.cs @@ -9,6 +9,48 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { public class NamespaceDirectiveTest { + [Fact] + public void TryComputeNamespace_IncompleteDirective_UsesEmptyNamespace() + { + // Arrange + var source = "c:\\foo\\bar\\bleh.cshtml"; + var imports = "c:\\foo\\baz\\bleh.cshtml"; + var node = new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan(imports, 0, 0, 0, 0), + }; + + // Act + var computed = NamespaceDirective.TryComputeNamespace(source, node, out var @namespace); + + // Assert + Assert.False(computed); + Assert.Equal(string.Empty, @namespace); + } + + [Fact] + public void TryComputeNamespace_EmptyDirective_UsesEmptyNamespace() + { + // Arrange + var source = "c:\\foo\\bar\\bleh.cshtml"; + var imports = "c:\\foo\\baz\\bleh.cshtml"; + var node = new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan(imports, 0, 0, 0, 0), + }; + node.Children.Add(new DirectiveTokenIRNode() { Content = string.Empty }); + node.Children[0].Parent = node; + + // Act + var computed = NamespaceDirective.TryComputeNamespace(source, node, out var @namespace); + + // Assert + Assert.False(computed); + Assert.Equal(string.Empty, @namespace); + } + // When we don't have a relationship between the source file and the imports file // we will just use the namespace on the node directly. [Theory] diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/RazorTemplateEngineTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/RazorTemplateEngineTest.cs index 75ca3e4acf..442d0b4b25 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/RazorTemplateEngineTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/RazorTemplateEngineTest.cs @@ -11,6 +11,53 @@ namespace Microsoft.AspNetCore.Razor.Language { public class RazorTemplateEngineTest { + [Fact] + public void GetImports_CanQueryInformationOnNonExistentFileWithoutImports() + { + // Arrange + var project = new TestRazorProject(); + var razorEngine = RazorEngine.Create(); + var templateEngine = new RazorTemplateEngine(razorEngine, project) + { + Options = + { + ImportsFileName = "MyImport.cshtml" + } + }; + var projectItemToQuery = project.GetItem("/Views/Home/Index.cshtml"); + + // Act + var imports = templateEngine.GetImports(projectItemToQuery); + + // Assert + Assert.Empty(imports); + } + + [Fact] + public void GetImports_CanQueryInformationOnNonExistentFileWithImports() + { + // Arrange + var path = "/Views/Home/MyImport.cshtml"; + var projectItem = new TestRazorProjectItem(path); + var project = new TestRazorProject(new[] { projectItem }); + var razorEngine = RazorEngine.Create(); + var templateEngine = new RazorTemplateEngine(razorEngine, project) + { + Options = + { + ImportsFileName = "MyImport.cshtml" + } + }; + var projectItemToQuery = project.GetItem("/Views/Home/Index.cshtml"); + + // Act + var imports = templateEngine.GetImports(projectItemToQuery); + + // Assert + var import = Assert.Single(imports); + Assert.Equal(projectItem.Path, import.FileName); + } + [Fact] public void GenerateCode_ThrowsIfItemCannotBeFound() {