diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultItemCollection.cs b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultItemCollection.cs new file mode 100644 index 0000000000..93b9a5149a --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultItemCollection.cs @@ -0,0 +1,43 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + internal class DefaultItemCollection : ItemCollection + { + private readonly Dictionary _items; + + public DefaultItemCollection() + { + _items = new Dictionary(); + } + + public override object this[object key] + { + get + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + object value; + _items.TryGetValue(key, out value); + return value; + } + + set + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + _items[key] = value; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorCodeDocument.cs b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorCodeDocument.cs new file mode 100644 index 0000000000..e29fc84d40 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorCodeDocument.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + internal class DefaultRazorCodeDocument : RazorCodeDocument + { + public DefaultRazorCodeDocument(RazorSourceDocument source) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + Source = source; + + Items = new DefaultItemCollection(); + } + + public override ItemCollection Items { get; } + + public override RazorSourceDocument Source { get; } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorEngine.cs b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorEngine.cs new file mode 100644 index 0000000000..57020a7417 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorEngine.cs @@ -0,0 +1,55 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + internal class DefaultRazorEngine : RazorEngine + { + public DefaultRazorEngine(IRazorEngineFeature[] features, IRazorEnginePhase[] phases) + { + if (features == null) + { + throw new ArgumentNullException(nameof(features)); + } + + if (phases == null) + { + throw new ArgumentNullException(nameof(phases)); + } + + Features = features; + Phases = phases; + + for (var i = 0; i < features.Length; i++) + { + features[i].Engine = this; + } + + for (var i = 0; i < phases.Length; i++) + { + phases[i].Engine = this; + } + } + + public override IReadOnlyList Features { get; } + + public override IReadOnlyList Phases { get; } + + public override void Process(RazorCodeDocument document) + { + if (document == null) + { + throw new ArgumentNullException(nameof(document)); + } + + for (var i = 0; i < Phases.Count; i++) + { + var phase = Phases[i]; + phase.Execute(document); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorEngineBuilder.cs b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorEngineBuilder.cs new file mode 100644 index 0000000000..d6c8515098 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorEngineBuilder.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + internal class DefaultRazorEngineBuilder : IRazorEngineBuilder + { + public DefaultRazorEngineBuilder() + { + Features = new List(); + Phases = new List(); + } + + public ICollection Features { get; } + + public IList Phases { get; } + + public RazorEngine Build() + { + var features = new IRazorEngineFeature[Features.Count]; + Features.CopyTo(features, arrayIndex: 0); + + var phases = new IRazorEnginePhase[Phases.Count]; + Phases.CopyTo(phases, arrayIndex: 0); + + return new DefaultRazorEngine(features, phases); + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorSourceDocument.cs b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorSourceDocument.cs new file mode 100644 index 0000000000..e28f76ae31 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorSourceDocument.cs @@ -0,0 +1,39 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Text; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + internal class DefaultRazorSourceDocument : RazorSourceDocument + { + private MemoryStream _stream; + + public DefaultRazorSourceDocument(MemoryStream stream, Encoding encoding, string filename) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + _stream = stream; + Encoding = encoding; + Filename = filename; + } + + public Encoding Encoding { get; } + + public override string Filename { get; } + + public override TextReader CreateReader() + { + var copy = new MemoryStream(_stream.ToArray()); + + return Encoding == null + ? new StreamReader(copy, detectEncodingFromByteOrderMarks: true) + : new StreamReader(copy, Encoding); + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/IRazorEngineBuilder.cs b/src/Microsoft.AspNetCore.Razor.Evolution/IRazorEngineBuilder.cs new file mode 100644 index 0000000000..5f7848a753 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/IRazorEngineBuilder.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public interface IRazorEngineBuilder + { + ICollection Features { get; } + + IList Phases { get; } + + RazorEngine Build(); + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/IRazorEngineFeature.cs b/src/Microsoft.AspNetCore.Razor.Evolution/IRazorEngineFeature.cs new file mode 100644 index 0000000000..017a65723b --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/IRazorEngineFeature.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public interface IRazorEngineFeature + { + RazorEngine Engine { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/IRazorEnginePhase.cs b/src/Microsoft.AspNetCore.Razor.Evolution/IRazorEnginePhase.cs new file mode 100644 index 0000000000..08dd34ba62 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/IRazorEnginePhase.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public interface IRazorEnginePhase + { + RazorEngine Engine { get; set; } + + void Execute(RazorCodeDocument document); + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/ItemCollection.cs b/src/Microsoft.AspNetCore.Razor.Evolution/ItemCollection.cs new file mode 100644 index 0000000000..3a7d0c261f --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/ItemCollection.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public abstract class ItemCollection + { + public abstract object this[object key] { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/RazorCodeDocument.cs b/src/Microsoft.AspNetCore.Razor.Evolution/RazorCodeDocument.cs new file mode 100644 index 0000000000..874af1992b --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/RazorCodeDocument.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public abstract class RazorCodeDocument + { + public static RazorCodeDocument Create(RazorSourceDocument source) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + return new DefaultRazorCodeDocument(source); + } + + public abstract ItemCollection Items { get; } + + public abstract RazorSourceDocument Source { get; } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/RazorEngine.cs b/src/Microsoft.AspNetCore.Razor.Evolution/RazorEngine.cs new file mode 100644 index 0000000000..0f26c3e27f --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/RazorEngine.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public abstract class RazorEngine + { + public static RazorEngine Create() + { + return Create(configure: null); + } + + public static RazorEngine Create(Action configure) + { + var builder = new DefaultRazorEngineBuilder(); + configure?.Invoke(builder); + return builder.Build(); + } + + public abstract IReadOnlyList Features { get; } + + public abstract IReadOnlyList Phases { get; } + + public abstract void Process(RazorCodeDocument document); + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/RazorSourceDocument.cs b/src/Microsoft.AspNetCore.Razor.Evolution/RazorSourceDocument.cs new file mode 100644 index 0000000000..631a17f15f --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/RazorSourceDocument.cs @@ -0,0 +1,49 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Text; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public abstract class RazorSourceDocument + { + public static RazorSourceDocument ReadFrom(Stream stream, string filename) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + return ReadFromInternal(stream, filename, encoding: null); + } + + public static RazorSourceDocument ReadFrom(Stream stream, string filename, Encoding encoding) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (encoding == null) + { + throw new ArgumentNullException(nameof(encoding)); + } + + return ReadFromInternal(stream, filename, encoding); + } + + private static RazorSourceDocument ReadFromInternal(Stream stream, string filename, Encoding encoding) + { + var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + + return new DefaultRazorSourceDocument(memoryStream, encoding, filename); + } + + public abstract string Filename { get; } + + public abstract TextReader CreateReader(); + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultItemCollectionTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultItemCollectionTest.cs new file mode 100644 index 0000000000..12ab1494e3 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultItemCollectionTest.cs @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class DefaultItemCollectionTest + { + [Fact] + public void Get_MissingValueReturnsNull() + { + // Arrange + var items = new DefaultItemCollection(); + + // Act + var value = items["foo"]; + + // Assert + Assert.Null(value); + } + + [Fact] + public void GetAndSet_ReturnsValue() + { + // Arrange + var items = new DefaultItemCollection(); + + var expected = "bar"; + items["foo"] = expected; + + // Act + var value = items["foo"]; + + // Assert + Assert.Same(expected, value); + } + + [Fact] + public void Set_CanSetValueToNull() + { + // Arrange + var items = new DefaultItemCollection(); + + items["foo"] = "bar"; + + // Act + items["foo"] = null; + + // Assert + Assert.Null(items["foo"]); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorCodeDocumentTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorCodeDocumentTest.cs new file mode 100644 index 0000000000..0616fcd449 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorCodeDocumentTest.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class DefaultRazorCodeDocumentTest + { + [Fact] + public void Ctor() + { + // Arrange + var source = TestRazorSourceDocument.Create(); + + // Act + var code = new DefaultRazorCodeDocument(source); + + // Assert + Assert.Same(source, code.Source); + Assert.NotNull(code.Items); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorEngineBuilderTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorEngineBuilderTest.cs new file mode 100644 index 0000000000..4be9486162 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorEngineBuilderTest.cs @@ -0,0 +1,42 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Linq; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class DefaultRazorEngineBuilderTest + { + [Fact] + public void Build_AddsFeaturesAndPhases() + { + // Arrange + var builder = new DefaultRazorEngineBuilder(); + + builder.Features.Add(Mock.Of()); + builder.Features.Add(Mock.Of()); + + builder.Phases.Add(Mock.Of()); + builder.Phases.Add(Mock.Of()); + + var features = builder.Features.ToArray(); + var phases = builder.Phases.ToArray(); + + // Act + var engine = builder.Build(); + + // Assert + Assert.Collection( + engine.Features, + f => Assert.Same(features[0], f), + f => Assert.Same(features[1], f)); + + Assert.Collection( + engine.Phases, + p => Assert.Same(phases[0], p), + p => Assert.Same(phases[1], p)); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorEngineTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorEngineTest.cs new file mode 100644 index 0000000000..3be3f0f69c --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorEngineTest.cs @@ -0,0 +1,72 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class DefaultRazorEngineTest + { + [Fact] + public void Ctor_InitializesPhasesAndFeatures() + { + // Arrange + var features = new IRazorEngineFeature[] + { + Mock.Of(), + Mock.Of(), + }; + + var phases = new IRazorEnginePhase[] + { + Mock.Of(), + Mock.Of(), + }; + + // Act + var engine = new DefaultRazorEngine(features, phases); + + // Assert + for (var i = 0; i < features.Length; i++) + { + Assert.Same(engine, features[i].Engine); + } + + for (var i = 0; i < phases.Length; i++) + { + Assert.Same(engine, phases[i].Engine); + } + } + + [Fact] + public void Process_CallsAllPhases() + { + // Arrange + var features = new IRazorEngineFeature[] + { + Mock.Of(), + Mock.Of(), + }; + + var phases = new IRazorEnginePhase[] + { + Mock.Of(), + Mock.Of(), + }; + + var engine = new DefaultRazorEngine(features, phases); + var document = TestRazorCodeDocument.CreateEmpty(); + + // Act + engine.Process(document); + + // Assert + for (var i = 0; i < phases.Length; i++) + { + var mock = Mock.Get(phases[i]); + mock.Verify(p => p.Execute(document), Times.Once()); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorSourceDocumentTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorSourceDocumentTest.cs new file mode 100644 index 0000000000..b1c9436fb3 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorSourceDocumentTest.cs @@ -0,0 +1,99 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Text; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class DefaultRazorSourceDocumentTest + { + [Fact] + public void Filename() + { + // Arrange + var content = CreateContent(); + + // Act + var document = new DefaultRazorSourceDocument(content, Encoding.UTF8, filename: "file.cshtml"); + + // Assert + Assert.Equal("file.cshtml", document.Filename); + } + + [Fact] + public void Filename_Null() + { + // Arrange + var content = CreateContent(); + + // Act + var document = new DefaultRazorSourceDocument(content, Encoding.UTF8, filename: null); + + // Assert + Assert.Null(document.Filename); + } + + [Fact] + public void CreateReader_WithEncoding() + { + // Arrange + var content = CreateContent("Hi", encoding: Encoding.UTF8); + var document = new DefaultRazorSourceDocument(content, Encoding.UTF8, filename: null); + + // Act + using (var reader = document.CreateReader()) + { + // Assert + Assert.Equal("Hi", reader.ReadToEnd()); + } + } + + [Fact] + public void CreateReader_Null_DetectsEncoding() + { + // Arrange + var content = CreateContent("Hi", encoding: Encoding.UTF32); + var document = new DefaultRazorSourceDocument(content, encoding: null, filename: null); + + // Act + using (var reader = document.CreateReader()) + { + // Assert + Assert.Equal("Hi", reader.ReadToEnd()); + } + } + + [Fact] + public void CreateReader_DisposeReader_DoesNotDirtyDocument() + { + // Arrange + var content = CreateContent("Hi", encoding: Encoding.UTF32); + var document = new DefaultRazorSourceDocument(content, encoding: null, filename: null); + + // Act & Assert + // + // (we should be able to do this twice to prove that the underlying data isn't disposed) + for (var i = 0; i < 2; i++) + { + using (var reader = document.CreateReader()) + { + // Assert + Assert.Equal("Hi", reader.ReadToEnd()); + } + } + } + + private static MemoryStream CreateContent(string content = "Hello, World!", Encoding encoding = null) + { + var stream = new MemoryStream(); + using (var writer = new StreamWriter(stream, encoding ?? Encoding.UTF8, bufferSize: 1024, leaveOpen: true)) + { + writer.Write(content); + } + + return stream; + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/IntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/IntegrationTest.cs new file mode 100644 index 0000000000..7fe96c1360 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/IntegrationTest.cs @@ -0,0 +1,25 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class IntegrationTest + { + [Fact] + public void BuildEngine_CallProcess() + { + // Arrange + var engine = RazorEngine.Create(); + + var document = RazorCodeDocument.Create(TestRazorSourceDocument.Create()); + + // Act + engine.Process(document); + + // Assert + // (nothing to verify yet) + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorCodeDocumentTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorCodeDocumentTest.cs new file mode 100644 index 0000000000..8c1a0bbe59 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorCodeDocumentTest.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class RazorCodeDocumentTest + { + [Fact] + public void Create() + { + // Arrange + var source = TestRazorSourceDocument.Create(); + + // Act + var code = RazorCodeDocument.Create(source); + + // Assert + Assert.Same(source, code.Source); + Assert.NotNull(code.Items); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorEngineTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorEngineTest.cs new file mode 100644 index 0000000000..e35f7d0874 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorEngineTest.cs @@ -0,0 +1,70 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Linq; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class RazorEngineTest + { + [Fact] + public void Create_NoArg_CreatesDefaultEngine() + { + // Arrange + // Act + var engine = RazorEngine.Create(); + + // Assert + Assert.IsType(engine); + Assert.Empty(engine.Features); + Assert.Empty(engine.Phases); + } + + [Fact] + public void Create_Null_CreatesDefaultEngine() + { + // Arrange + // Act + var engine = RazorEngine.Create(configure: null); + + // Assert + Assert.IsType(engine); + Assert.Empty(engine.Features); + Assert.Empty(engine.Phases); + } + + [Fact] + public void Create_Lambda_AddsFeaturesAndPhases() + { + // Arrange + IRazorEngineFeature[] features = null; + IRazorEnginePhase[] phases = null; + + // Act + var engine = RazorEngine.Create(builder => + { + builder.Features.Add(Mock.Of()); + builder.Features.Add(Mock.Of()); + + builder.Phases.Add(Mock.Of()); + builder.Phases.Add(Mock.Of()); + + features = builder.Features.ToArray(); + phases = builder.Phases.ToArray(); + }); + + // Assert + Assert.Collection( + engine.Features, + f => Assert.Same(features[0], f), + f => Assert.Same(features[1], f)); + + Assert.Collection( + engine.Phases, + p => Assert.Same(phases[0], p), + p => Assert.Same(phases[1], p)); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorSourceDocumentTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorSourceDocumentTest.cs new file mode 100644 index 0000000000..87d85b5764 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorSourceDocumentTest.cs @@ -0,0 +1,39 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Text; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class RazorSourceDocumentTest + { + [Fact] + public void Create() + { + // Arrange + var content = TestRazorSourceDocument.CreateContent(); + + // Act + var document = RazorSourceDocument.ReadFrom(content, "file.cshtml"); + + // Assert + Assert.Equal("file.cshtml", document.Filename); + Assert.Null(Assert.IsType(document).Encoding); + } + + [Fact] + public void Create_WithEncoding() + { + // Arrange + var content = TestRazorSourceDocument.CreateContent(encoding: Encoding.UTF32); + + // Act + var document = RazorSourceDocument.ReadFrom(content, "file.cshtml", Encoding.UTF32); + + // Assert + Assert.Equal("file.cshtml", document.Filename); + Assert.Same(Encoding.UTF32, Assert.IsType(document).Encoding); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorCodeDocument.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorCodeDocument.cs new file mode 100644 index 0000000000..7cb0668e3f --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorCodeDocument.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + internal class TestRazorCodeDocument : DefaultRazorCodeDocument + { + public static TestRazorCodeDocument CreateEmpty() + { + var source = TestRazorSourceDocument.Create(content: string.Empty); + return new TestRazorCodeDocument(source); + } + + private TestRazorCodeDocument(RazorSourceDocument source) + : base(source) + { + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorSourceDocument.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorSourceDocument.cs new file mode 100644 index 0000000000..0fb1b37056 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorSourceDocument.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Text; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + internal class TestRazorSourceDocument : DefaultRazorSourceDocument + { + public static MemoryStream CreateContent(string content = "Hello, World!", Encoding encoding = null) + { + var stream = new MemoryStream(); + using (var writer = new StreamWriter(stream, encoding ?? Encoding.UTF8, bufferSize: 1024, leaveOpen: true)) + { + writer.Write(content); + } + + stream.Seek(0L, SeekOrigin.Begin); + + return stream; + } + + public static RazorSourceDocument Create(string content = "Hello, world!", Encoding encoding = null) + { + var stream = CreateContent(content, encoding); + return new TestRazorSourceDocument(stream, encoding ?? Encoding.UTF8, "test.cshtml"); + } + + public TestRazorSourceDocument(MemoryStream stream, Encoding encoding, string filename) + : base(stream, encoding, filename) + { + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/project.json b/test/Microsoft.AspNetCore.Razor.Evolution.Test/project.json index 285620980c..725e4d54a0 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/project.json +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/project.json @@ -3,6 +3,7 @@ "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Razor.Evolution": "1.1.0-*", + "Moq": "4.6.36-*", "xunit": "2.2.0-*" }, "testRunner": "xunit",