text:
using System.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Microsoft.Extensions.WebEncoders.Testing;
using Moq;

namespace Microsoft.AspNetCore.Mvc.Razor;

public class RazorViewEngineTest
{
    private static readonly Dictionary<string, object> _areaTestContext = new Dictionary<string, object>()
        {
            {"area", "foo"},
            {"controller", "bar"},
        };

    private static readonly Dictionary<string, object> _controllerTestContext = new Dictionary<string, object>()
        {
            {"controller", "bar"},
        };

    private static readonly Dictionary<string, object> _pageTestContext = new Dictionary<string, object>()
        {
            {"page", "/Accounts/Index"},
        };

    public static IEnumerable<object[]> AbsoluteViewPathData
    {
        get
        {
            yield return new[] { "~/foo/bar" };
            yield return new[] { "/foo/bar" };
            yield return new[] { "~/foo/bar.txt" };
            yield return new[] { "/foo/bar.txt" };
        }
    }

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    public void FindView_IsMainPage_ThrowsIfViewNameIsNullOrEmpty(string viewName)
    {
        // Arrange
        var viewEngine = CreateViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act & Assert
        ExceptionAssert.ThrowsArgumentNullOrEmpty(
            () => viewEngine.FindView(context, viewName, isMainPage: true),
            "viewName");
    }

    [Theory]
    [MemberData(nameof(AbsoluteViewPathData))]
    public void FindView_IsMainPage_WithFullPath_ReturnsNotFound(string viewName)
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindView(context, viewName, isMainPage: true);

        // Assert
        Assert.False(result.Success);
    }

    [Theory]
    [MemberData(nameof(AbsoluteViewPathData))]
    public void FindView_IsMainPage_WithFullPathAndCshtmlEnding_ReturnsNotFound(string viewName)
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();
        var context = GetActionContext(_controllerTestContext);
        viewName += ".cshtml";

        // Act
        var result = viewEngine.FindView(context, viewName, isMainPage: true);

        // Assert
        Assert.False(result.Success);
    }

    [Theory]
    [InlineData(false)]
    [InlineData(true)]
    public void FindView_WithRelativePath_ReturnsNotFound(bool isMainPage)
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindView(context, "View.cshtml", isMainPage);

        // Assert
        Assert.False(result.Success);
    }

    [Theory]
    [InlineData(false)]
    [InlineData(true)]
    public void GetView_WithViewName_ReturnsNotFound(bool isMainPage)
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();

        // Act
        var result = viewEngine.GetView("~/Home/View1.cshtml", "View2", isMainPage);

        // Assert
        Assert.False(result.Success);
    }

    [Fact]
    public void FindView_ReturnsRazorView_IfLookupWasSuccessful()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        var viewStart1 = Mock.Of<IRazorPage>();
        var viewStart2 = Mock.Of<IRazorPage>();

        pageFactory
            .Setup(p => p.CreateFactory("/Views/bar/test-view.cshtml"))
            .Returns(GetPageFactoryResult(() => page));

        pageFactory
            .Setup(p => p.CreateFactory("/Views/_ViewStart.cshtml"))
            .Returns(GetPageFactoryResult(() => viewStart2));

        pageFactory
            .Setup(p => p.CreateFactory("/_ViewStart.cshtml"))
            .Returns(GetPageFactoryResult(() => viewStart1));

        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindView(context, "test-view", isMainPage: false);

        // Assert
        Assert.True(result.Success);
        var view = Assert.IsType<RazorView>(result.View);
        Assert.Same(page, view.RazorPage);
        Assert.Equal("test-view", result.ViewName);
        Assert.Empty(view.ViewStartPages);
    }

    [Fact]
    public void FindView_DoesNotExpireCachedResults_IfViewStartsExpire()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        var viewStart = Mock.Of<IRazorPage>();
        var cancellationTokenSource = new CancellationTokenSource();
        var changeToken = new CancellationChangeToken(cancellationTokenSource.Token);

        pageFactory
            .Setup(p => p.CreateFactory("/Views/bar/test-view.cshtml"))
            .Returns(GetPageFactoryResult(() => page));

        pageFactory
            .Setup(p => p.CreateFactory("/Views/_ViewStart.cshtml"))
            .Returns(GetPageFactoryResult(() => viewStart, new[] { changeToken }));

        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(_controllerTestContext);

        // Act - 1
        var result1 = viewEngine.FindView(context, "test-view", isMainPage: false);

        // Assert - 1
        Assert.True(result1.Success);
        var view1 = Assert.IsType<RazorView>(result1.View);
        Assert.Same(page, view1.RazorPage);
        Assert.Equal("test-view", result1.ViewName);
        Assert.Empty(view1.ViewStartPages);

        // Act - 2
        cancellationTokenSource.Cancel();
        var result2 = viewEngine.FindView(context, "test-view", isMainPage: false);

        // Assert - 2
        Assert.True(result2.Success);
        var view2 = Assert.IsType<RazorView>(result2.View);
        Assert.Same(page, view2.RazorPage);
        pageFactory.Verify(p => p.CreateFactory("/Views/bar/test-view.cshtml"), Times.Once());
    }

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    public void FindView_ThrowsIfViewNameIsNullOrEmpty(string partialViewName)
    {
        // Arrange
        var viewEngine = CreateViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act & Assert
        ExceptionAssert.ThrowsArgumentNullOrEmpty(
            () => viewEngine.FindView(context, partialViewName, isMainPage: false),
            "viewName");
    }

    [Theory]
    [MemberData(nameof(AbsoluteViewPathData))]
    public void FindViewWithFullPath_ReturnsNotFound(string partialViewName)
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindView(context, partialViewName, isMainPage: false);

        // Assert
        Assert.False(result.Success);
    }

    [Theory]
    [MemberData(nameof(AbsoluteViewPathData))]
    public void FindViewWithFullPathAndCshtmlEnding_ReturnsNotFound(string partialViewName)
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();
        var context = GetActionContext(_controllerTestContext);
        partialViewName += ".cshtml";

        // Act
        var result = viewEngine.FindView(context, partialViewName, isMainPage: false);

        // Assert
        Assert.False(result.Success);
    }

    [Theory]
    [InlineData(true)]
    [InlineData(false)]
    public void FindView_FailsButSearchesCorrectLocationsWithAreas(bool isMainPage)
    {
        // Arrange
        var viewEngine = CreateViewEngine();
        var context = GetActionContext(_areaTestContext);

        // Act
        var result = viewEngine.FindView(context, "viewName", isMainPage);

        // Assert
        Assert.False(result.Success);
        Assert.Equal(new[]
        {
                "/Areas/foo/Views/bar/viewName.cshtml",
                "/Areas/foo/Views/Shared/viewName.cshtml",
                "/Views/Shared/viewName.cshtml",
            }, result.SearchedLocations);
    }

    [Theory]
    [InlineData(true)]
    [InlineData(false)]
    public void FindView_FailsButSearchesCorrectLocationsWithoutAreas(bool isMainPage)
    {
        // Arrange
        var viewEngine = CreateViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindView(context, "viewName", isMainPage);

        // Assert
        Assert.False(result.Success);
        Assert.Equal(new[] {
                "/Views/bar/viewName.cshtml",
                "/Views/Shared/viewName.cshtml",
            }, result.SearchedLocations);
    }

    [Fact]
    public void FindView_IsMainPage_ReturnsRazorView_IfLookupWasSuccessful()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        var viewStart1 = Mock.Of<IRazorPage>();
        var viewStart2 = Mock.Of<IRazorPage>();

        pageFactory
            .Setup(p => p.CreateFactory("/Views/bar/test-view.cshtml"))
            .Returns(GetPageFactoryResult(() => page));

        pageFactory
            .Setup(p => p.CreateFactory("/Views/_ViewStart.cshtml"))
            .Returns(GetPageFactoryResult(() => viewStart2));

        pageFactory
            .Setup(p => p.CreateFactory("/_ViewStart.cshtml"))
            .Returns(GetPageFactoryResult(() => viewStart1));

        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindView(context, "test-view", isMainPage: true);

        // Assert
        Assert.True(result.Success);
        var view = Assert.IsType<RazorView>(result.View);
        Assert.Equal("test-view", result.ViewName);
        Assert.Same(page, view.RazorPage);

        // ViewStartPages is not empty as it is in FindView_ReturnsRazorView_IfLookupWasSuccessful() despite
        // (faked) existence of the view start files in both tests.
        Assert.Equal(new[] { viewStart1, viewStart2 }, view.ViewStartPages);
    }

    [Fact]
    public void FindView_UsesViewLocationFormat_IfRouteDoesNotContainArea()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();

        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory("fake-path1/bar/test-view.rzr"))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor(
                viewLocationFormats: new[] { "fake-path1/{1}/{0}.rzr" },
                areaViewLocationFormats: new[] { "fake-area-path/{2}/{1}/{0}.rzr" }));
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindView(context, "test-view", isMainPage: true);

        // Assert
        pageFactory.Verify();
        var view = Assert.IsType<RazorView>(result.View);
        Assert.Same(page, view.RazorPage);
    }

    [Fact]
    public void FindView_UsesAreaViewLocationFormat_IfRouteContainsArea()
    {
        // Arrange
        var viewName = "test-view2";
        var expectedViewName = "fake-area-path/foo/bar/test-view2.rzr";
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory(expectedViewName))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor(
                viewLocationFormats: new[] { "fake-path1/{1}/{0}.rzr" },
                areaViewLocationFormats: new[] { "fake-area-path/{2}/{1}/{0}.rzr" }));
        var context = GetActionContext(_areaTestContext);

        // Act
        var result = viewEngine.FindView(context, viewName, isMainPage: true);

        // Assert
        Assert.True(result.Success);
        Assert.Equal(viewName, result.ViewName);
        pageFactory.Verify();
    }

    [Theory]
    [InlineData("Test-View.cshtml")]
    [InlineData("/Home/Test-View.cshtml")]
    public void GetView_DoesNotUseViewLocationFormat_WithRelativePath_IfRouteDoesNotContainArea(string viewName)
    {
        // Arrange
        var expectedViewName = "/Home/Test-View.cshtml";
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory(expectedViewName))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act
        var result = viewEngine.GetView("/Home/Page.cshtml", viewName, isMainPage: true);

        // Assert
        Assert.True(result.Success);
        Assert.Equal(viewName, result.ViewName);
        pageFactory.Verify();
    }

    [Theory]
    [InlineData("Test-View.cshtml")]
    [InlineData("/Home/Test-View.cshtml")]
    public void GetView_DoesNotUseViewLocationFormat_WithRelativePath_IfRouteContainArea(string viewName)
    {
        // Arrange
        var expectedViewName = "/Home/Test-View.cshtml";
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory(expectedViewName))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act
        var result = viewEngine.GetView("/Home/Page.cshtml", viewName, isMainPage: true);

        // Assert
        Assert.True(result.Success);
        Assert.Equal(viewName, result.ViewName);
        pageFactory.Verify();
    }

    [Theory]
    [InlineData("/Test-View.cshtml")]
    [InlineData("~/Test-View.CSHTML")]
    [InlineData("/Home/Test-View.CSHTML")]
    [InlineData("~/Home/Test-View.cshtml")]
    [InlineData("~/SHARED/TEST-VIEW.CSHTML")]
    public void GetView_UsesGivenPath_WithAppRelativePath(string viewName)
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory(viewName))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act
        var result = viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);

        // Assert
        Assert.True(result.Success);
        Assert.Equal(viewName, result.ViewName);
        pageFactory.Verify();
    }

    [Theory]
    [InlineData("Test-View.cshtml")]
    [InlineData("Test-View.CSHTML")]
    [InlineData("PATH/TEST-VIEW.CSHTML")]
    [InlineData("Path1/Path2/Test-View.cshtml")]
    public void GetView_ResolvesRelativeToCurrentPage_WithRelativePath(string viewName)
    {
        // Arrange
        var expectedViewName = $"/Home/{ viewName }";
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory(expectedViewName))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act
        var result = viewEngine.GetView("/Home/Page.cshtml", viewName, isMainPage: true);

        // Assert
        Assert.True(result.Success);
        Assert.Equal(viewName, result.ViewName);
        pageFactory.Verify();
    }

    [Theory]
    [InlineData("Test-View.cshtml")]
    [InlineData("Test-View.CSHTML")]
    [InlineData("PATH/TEST-VIEW.CSHTML")]
    [InlineData("Path1/Path2/Test-View.cshtml")]
    public void GetView_ResolvesRelativeToAppRoot_WithRelativePath_IfNoPageExecuting(string viewName)
    {
        // Arrange
        var expectedViewName = $"/{ viewName }";
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory(expectedViewName))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act
        var result = viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);

        // Assert
        Assert.True(result.Success);
        Assert.Equal(viewName, result.ViewName);
        pageFactory.Verify();
        var view = Assert.IsType<RazorView>(result.View);
        Assert.Same(page, view.RazorPage);
    }

    [Theory]
    [InlineData(false)]
    [InlineData(true)]
    public void FindView_CreatesDifferentCacheEntries_ForAreaViewsAndNonAreaViews(bool isMainPage)
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var areaPage = Mock.Of<IRazorPage>();
        var nonAreaPage = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory("/Areas/Admin/Views/Home/Index.cshtml"))
            .Returns(GetPageFactoryResult(() => areaPage));
        pageFactory
            .Setup(p => p.CreateFactory("/Views/Home/Index.cshtml"))
            .Returns(GetPageFactoryResult(() => nonAreaPage));

        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act 1
        var areaContext = GetActionContext(new Dictionary<string, object>()
            {
                {"area", "Admin"},
                {"controller", "Home"},
            });
        var result1 = viewEngine.FindView(areaContext, "Index", isMainPage);

        // Assert 1
        Assert.NotNull(result1);
        pageFactory.Verify(p => p.CreateFactory("/Areas/Admin/Views/Home/Index.cshtml"), Times.Once());
        pageFactory.Verify(p => p.CreateFactory("/Views/Home/Index.cshtml"), Times.Never());
        var view1 = Assert.IsType<RazorView>(result1.View);
        Assert.Same(areaPage, view1.RazorPage);

        // Act 2
        var nonAreaContext = GetActionContext(new Dictionary<string, object>()
            {
                {"controller", "Home"},
            });
        var result2 = viewEngine.FindView(nonAreaContext, "Index", isMainPage);

        // Assert 2
        Assert.NotNull(result2);
        pageFactory.Verify(p => p.CreateFactory("/Areas/Admin/Views/Home/Index.cshtml"), Times.Once());
        pageFactory.Verify(p => p.CreateFactory("/Views/Home/Index.cshtml"), Times.Once());
        var view2 = Assert.IsType<RazorView>(result2.View);
        Assert.Same(nonAreaPage, view2.RazorPage);

        // Act 3
        // Ensure we're getting cached results.
        var result3 = viewEngine.FindView(areaContext, "Index", isMainPage);
        var result4 = viewEngine.FindView(nonAreaContext, "Index", isMainPage);

        // Assert 4
        pageFactory.Verify(p => p.CreateFactory("/Areas/Admin/Views/Home/Index.cshtml"), Times.Once());
        pageFactory.Verify(p => p.CreateFactory("/Views/Home/Index.cshtml"), Times.Once());

        var view3 = Assert.IsType<RazorView>(result3.View);
        Assert.Same(areaPage, view3.RazorPage);
        var view4 = Assert.IsType<RazorView>(result4.View);
        Assert.Same(nonAreaPage, view4.RazorPage);
    }

    [Theory]
    [InlineData(false)]
    [InlineData(true)]
    public void FindView_CreatesDifferentCacheEntries_ForDifferentAreas(bool isMainPage)
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var areaPage1 = Mock.Of<IRazorPage>();
        var areaPage2 = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory("/Areas/Marketing/Views/Home/Index.cshtml"))
            .Returns(GetPageFactoryResult(() => areaPage1));
        pageFactory
            .Setup(p => p.CreateFactory("/Areas/Sales/Views/Home/Index.cshtml"))
            .Returns(GetPageFactoryResult(() => areaPage2));

        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act 1
        var areaContext1 = GetActionContext(new Dictionary<string, object>()
            {
                {"area", "Marketing"},
                {"controller", "Home"},
            });
        var result1 = viewEngine.FindView(areaContext1, "Index", isMainPage);

        // Assert 1
        Assert.NotNull(result1);
        pageFactory.Verify(p => p.CreateFactory("/Areas/Marketing/Views/Home/Index.cshtml"), Times.Once());
        pageFactory.Verify(p => p.CreateFactory("/Areas/Sales/Views/Home/Index.cshtml"), Times.Never());
        var view1 = Assert.IsType<RazorView>(result1.View);
        Assert.Same(areaPage1, view1.RazorPage);

        // Act 2
        var areaContext2 = GetActionContext(new Dictionary<string, object>()
            {
                {"controller", "Home"},
                {"area", "Sales"},
            });
        var result2 = viewEngine.FindView(areaContext2, "Index", isMainPage);

        // Assert 2
        Assert.NotNull(result2);
        pageFactory.Verify(p => p.CreateFactory("/Areas/Marketing/Views/Home/Index.cshtml"), Times.Once());
        pageFactory.Verify(p => p.CreateFactory("/Areas/Sales/Views/Home/Index.cshtml"), Times.Once());
        var view2 = Assert.IsType<RazorView>(result2.View);
        Assert.Same(areaPage2, view2.RazorPage);

        // Act 3
        // Ensure we're getting cached results.
        var result3 = viewEngine.FindView(areaContext1, "Index", isMainPage);
        var result4 = viewEngine.FindView(areaContext2, "Index", isMainPage);

        // Assert 4
        pageFactory.Verify(p => p.CreateFactory("/Areas/Marketing/Views/Home/Index.cshtml"), Times.Once());
        pageFactory.Verify(p => p.CreateFactory("/Areas/Sales/Views/Home/Index.cshtml"), Times.Once());

        var view3 = Assert.IsType<RazorView>(result3.View);
        Assert.Same(areaPage1, view3.RazorPage);
        var view4 = Assert.IsType<RazorView>(result4.View);
        Assert.Same(areaPage2, view4.RazorPage);
    }

    [Fact]
    public void FindView_UsesViewLocationExpandersToLocateViews()
    {
        // Arrange
        var routeValues = _controllerTestContext;
        var expectedSeeds = new[]
        {
                "/Views/{1}/{0}.cshtml",
                "/Views/Shared/{0}.cshtml"
            };

        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
            .Setup(p => p.CreateFactory("test-string/bar.cshtml"))
            .Returns(GetPageFactoryResult(() => Mock.Of<IRazorPage>()))
            .Verifiable();

        var expander1Result = new[] { "some-seed" };
        var expander1 = new Mock<IViewLocationExpander>();
        expander1
            .Setup(e => e.PopulateValues(It.IsAny<ViewLocationExpanderContext>()))
            .Callback((ViewLocationExpanderContext c) =>
            {
                Assert.NotNull(c.ActionContext);
                c.Values["expander-key"] = expander1.ToString();
            })
            .Verifiable();
        expander1
            .Setup(e => e.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Callback((ViewLocationExpanderContext c, IEnumerable<string> seeds) =>
            {
                Assert.NotNull(c.ActionContext);
                Assert.Equal(expectedSeeds, seeds);
            })
            .Returns(expander1Result)
            .Verifiable();

        var expander2 = new Mock<IViewLocationExpander>();
        expander2
            .Setup(e => e.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Callback((ViewLocationExpanderContext c, IEnumerable<string> seeds) =>
            {
                Assert.Equal(expander1Result, seeds);
            })
            .Returns(new[] { "test-string/{1}.cshtml" })
            .Verifiable();

        var viewEngine = CreateViewEngine(
            pageFactory.Object,
            new[] { expander1.Object, expander2.Object });
        var context = GetActionContext(routeValues);

        // Act
        var result = viewEngine.FindView(context, "test-view", isMainPage: true);

        // Assert
        Assert.True(result.Success);
        Assert.IsAssignableFrom<IView>(result.View);
        pageFactory.Verify();
        expander1.Verify();
        expander2.Verify();
    }

    [Fact]
    public void FindView_UsesViewLocationExpandersToLocateViews_ForAreas()
    {
        // Arrange
        var routeValues = _areaTestContext;
        var expectedSeeds = new[]
        {
                "/Areas/{2}/Views/{1}/{0}.cshtml",
                "/Areas/{2}/Views/Shared/{0}.cshtml",
                "/Views/Shared/{0}.cshtml"
            };

        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
            .Setup(p => p.CreateFactory("test-string/bar.cshtml"))
            .Returns(GetPageFactoryResult(() => Mock.Of<IRazorPage>()))
            .Verifiable();

        var expander1Result = new[] { "some-seed" };
        var expander1 = new Mock<IViewLocationExpander>();
        expander1
            .Setup(e => e.PopulateValues(It.IsAny<ViewLocationExpanderContext>()))
            .Callback((ViewLocationExpanderContext c) =>
            {
                Assert.NotNull(c.ActionContext);
                c.Values["expander-key"] = expander1.ToString();
            })
            .Verifiable();
        expander1
            .Setup(e => e.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Callback((ViewLocationExpanderContext c, IEnumerable<string> seeds) =>
            {
                Assert.NotNull(c.ActionContext);
                Assert.Equal(expectedSeeds, seeds);
            })
            .Returns(expander1Result)
            .Verifiable();

        var expander2 = new Mock<IViewLocationExpander>();
        expander2
            .Setup(e => e.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Callback((ViewLocationExpanderContext c, IEnumerable<string> seeds) =>
            {
                Assert.Equal(expander1Result, seeds);
            })
            .Returns(new[] { "test-string/{1}.cshtml" })
            .Verifiable();

        var viewEngine = CreateViewEngine(
            pageFactory.Object,
            new[] { expander1.Object, expander2.Object });
        var context = GetActionContext(routeValues);

        // Act
        var result = viewEngine.FindView(context, "test-view", isMainPage: true);

        // Assert
        Assert.True(result.Success);
        Assert.IsAssignableFrom<IView>(result.View);
        pageFactory.Verify();
        expander1.Verify();
        expander2.Verify();
    }

    [Fact]
    public void FindView_NormalizesPaths_ReturnedByViewLocationExpanders()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
            .Setup(p => p.CreateFactory(@"Views\Home\Index.cshtml"))
            .Returns(GetPageFactoryResult(() => Mock.Of<IRazorPage>()))
            .Verifiable();

        var expander = new Mock<IViewLocationExpander>();
        expander
            .Setup(e => e.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Returns(new[] { @"Views\Home\Index.cshtml" });

        var viewEngine = CreateViewEngine(
            pageFactory.Object,
            new[] { expander.Object });
        var context = GetActionContext(new Dictionary<string, object>());

        // Act
        var result = viewEngine.FindView(context, "test-view", isMainPage: true);

        // Assert
        Assert.True(result.Success);
        Assert.IsAssignableFrom<IView>(result.View);
        pageFactory.Verify();
    }

    [Fact]
    public void FindView_CachesValuesIfViewWasFound()
    {
        // Arrange
        var page = Mock.Of<IRazorPage>();
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
            .Setup(p => p.CreateFactory("/Views/bar/baz.cshtml"))
            .Returns(GetPageFactoryResult(factory: null))
            .Verifiable();
        pageFactory
           .Setup(p => p.CreateFactory("/Views/Shared/baz.cshtml"))
           .Returns(GetPageFactoryResult(() => page))
           .Verifiable();

        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(_controllerTestContext);

        // Act 1
        var result1 = viewEngine.FindView(context, "baz", isMainPage: true);

        // Assert 1
        Assert.True(result1.Success);
        var view1 = Assert.IsType<RazorView>(result1.View);
        Assert.Same(page, view1.RazorPage);
        pageFactory.Verify();

        // Act 2
        pageFactory
           .Setup(p => p.CreateFactory(It.IsAny<string>()))
           .Throws(new Exception("Shouldn't be called"));

        var result2 = viewEngine.FindView(context, "baz", isMainPage: true);

        // Assert 2
        Assert.True(result2.Success);
        var view2 = Assert.IsType<RazorView>(result2.View);
        Assert.Same(page, view2.RazorPage);
        pageFactory.Verify();
    }

    [Fact]
    public void FindView_CachesValuesIfViewWasFound_ForPages()
    {
        // Arrange
        var page = Mock.Of<IRazorPage>();
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
           .Setup(p => p.CreateFactory("/Views/Shared/baz.cshtml"))
           .Returns(GetPageFactoryResult(() => page))
           .Verifiable();

        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(_pageTestContext);

        // Act 1
        var result1 = viewEngine.FindView(context, "baz", isMainPage: false);

        // Assert 1
        Assert.True(result1.Success);
        var view1 = Assert.IsType<RazorView>(result1.View);
        Assert.Same(page, view1.RazorPage);
        pageFactory.Verify();

        // Act 2
        pageFactory
           .Setup(p => p.CreateFactory(It.IsAny<string>()))
           .Throws(new Exception("Shouldn't be called"));

        var result2 = viewEngine.FindView(context, "baz", isMainPage: false);

        // Assert 2
        Assert.True(result2.Success);
        var view2 = Assert.IsType<RazorView>(result2.View);
        Assert.Same(page, view2.RazorPage);
        pageFactory.Verify();
    }

    [Fact]
    public void FindView_InvokesPageFactoryIfChangeTokenExpired()
    {
        // Arrange
        var page1 = Mock.Of<IRazorPage>();
        var page2 = Mock.Of<IRazorPage>();
        var sequence = new MockSequence();
        var cancellationTokenSource = new CancellationTokenSource();
        var changeToken = new CancellationChangeToken(cancellationTokenSource.Token);

        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
            .InSequence(sequence)
            .Setup(p => p.CreateFactory("/Views/bar/baz.cshtml"))
            .Returns(GetPageFactoryResult(factory: null, changeTokens: new[] { changeToken }));
        pageFactory
           .InSequence(sequence)
           .Setup(p => p.CreateFactory("/Views/Shared/baz.cshtml"))
           .Returns(GetPageFactoryResult(() => page1))
           .Verifiable();
        pageFactory
            .InSequence(sequence)
            .Setup(p => p.CreateFactory("/Views/bar/baz.cshtml"))
            .Returns(GetPageFactoryResult(() => page2));

        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(_controllerTestContext);

        // Act 1
        var result1 = viewEngine.FindView(context, "baz", isMainPage: true);

        // Assert 1
        Assert.True(result1.Success);
        var view1 = Assert.IsType<RazorView>(result1.View);
        Assert.Same(page1, view1.RazorPage);

        // Act 2
        cancellationTokenSource.Cancel();
        var result2 = viewEngine.FindView(context, "baz", isMainPage: true);

        // Assert 2
        Assert.True(result2.Success);
        var view2 = Assert.IsType<RazorView>(result2.View);
        Assert.Same(page2, view2.RazorPage);
        pageFactory.Verify();
    }

    // This test validates an important perf scenario of RazorViewEngine not constructing
    // multiple strings for views that do not exist in the file system on a per-request basis.
    [Fact]
    public void FindView_DoesNotInvokeViewLocationExpanders_IfChangeTokenHasNotExpired()
    {
        // Arrange
        var pageFactory = Mock.Of<IRazorPageFactoryProvider>();
        var expander = new Mock<IViewLocationExpander>();
        var expandedLocations = new[]
        {
                "viewlocation1",
                "viewlocation2",
                "viewlocation3",
            };
        expander
            .Setup(v => v.PopulateValues(It.IsAny<ViewLocationExpanderContext>()))
            .Callback((ViewLocationExpanderContext expanderContext) =>
            {
                expanderContext.Values["somekey"] = "somevalue";
            })
            .Verifiable();
        expander
            .Setup(v => v.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Returns(expandedLocations)
            .Verifiable();

        var viewEngine = CreateViewEngine(
            pageFactory,
            expanders: new[] { expander.Object });
        var context = GetActionContext(_controllerTestContext);

        // Act - 1
        var result = viewEngine.FindView(context, "myview", isMainPage: true);

        // Assert - 1
        Assert.False(result.Success);
        Assert.Equal(expandedLocations, result.SearchedLocations);
        expander.Verify();

        // Act - 2
        result = viewEngine.FindView(context, "myview", isMainPage: true);

        // Assert - 2
        Assert.False(result.Success);
        Assert.Equal(expandedLocations, result.SearchedLocations);
        expander.Verify(
            v => v.PopulateValues(It.IsAny<ViewLocationExpanderContext>()),
            Times.Exactly(2));
        expander.Verify(
            v => v.ExpandViewLocations(It.IsAny<ViewLocationExpanderContext>(), It.IsAny<IEnumerable<string>>()),
            Times.Once());
    }

    [Fact]
    public void FindView_InvokesViewLocationExpanders_IfChangeTokenExpires()
    {
        // Arrange
        var cancellationTokenSource = new CancellationTokenSource();
        var changeToken = new CancellationChangeToken(cancellationTokenSource.Token);
        var page = Mock.Of<IRazorPage>();
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
            .Setup(p => p.CreateFactory("viewlocation3"))
            .Returns(GetPageFactoryResult(factory: null, changeTokens: new[] { changeToken }));
        var expander = new Mock<IViewLocationExpander>();
        var expandedLocations = new[]
        {
                "viewlocation1",
                "viewlocation2",
                "viewlocation3",
            };
        expander
            .Setup(v => v.PopulateValues(It.IsAny<ViewLocationExpanderContext>()))
            .Callback((ViewLocationExpanderContext expanderContext) =>
            {
                expanderContext.Values["somekey"] = "somevalue";
            })
            .Verifiable();
        expander
            .Setup(v => v.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Returns(expandedLocations)
            .Verifiable();

        var viewEngine = CreateViewEngine(
            pageFactory.Object,
            expanders: new[] { expander.Object });
        var context = GetActionContext(_controllerTestContext);

        // Act - 1
        var result = viewEngine.FindView(context, "MyView", isMainPage: true);

        // Assert - 1
        Assert.False(result.Success);
        Assert.Equal(expandedLocations, result.SearchedLocations);
        expander.Verify();

        // Act - 2
        pageFactory
            .Setup(p => p.CreateFactory("viewlocation3"))
            .Returns(GetPageFactoryResult(() => page));
        cancellationTokenSource.Cancel();
        result = viewEngine.FindView(context, "MyView", isMainPage: true);

        // Assert - 2
        Assert.True(result.Success);
        var view = Assert.IsType<RazorView>(result.View);
        Assert.Same(page, view.RazorPage);
        expander.Verify(
            v => v.PopulateValues(It.IsAny<ViewLocationExpanderContext>()),
            Times.Exactly(2));
        expander.Verify(
            v => v.ExpandViewLocations(It.IsAny<ViewLocationExpanderContext>(), It.IsAny<IEnumerable<string>>()),
            Times.Exactly(2));
    }

    [Theory]
    [MemberData(nameof(AbsoluteViewPathData))]
    public void FindPage_WithFullPath_ReturnsNotFound(string viewName)
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindPage(context, viewName);

        // Assert
        Assert.Null(result.Page);
    }

    [Theory]
    [MemberData(nameof(AbsoluteViewPathData))]
    public void FindPage_WithFullPathAndCshtmlEnding_ReturnsNotFound(string viewName)
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();
        var context = GetActionContext(_controllerTestContext);
        viewName += ".cshtml";

        // Act
        var result = viewEngine.FindPage(context, viewName);

        // Assert
        Assert.Null(result.Page);
    }

    [Fact]
    public void FindPage_WithRelativePath_ReturnsNotFound()
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindPage(context, "View.cshtml");

        // Assert
        Assert.Null(result.Page);
    }

    [Fact]
    public void GetPage_WithViewName_ReturnsNotFound()
    {
        // Arrange
        var viewEngine = CreateSuccessfulViewEngine();

        // Act
        var result = viewEngine.GetPage("~/Home/View1.cshtml", "View2");

        // Assert
        Assert.Null(result.Page);
    }

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    public void FindPage_ThrowsIfNameIsNullOrEmpty(string pageName)
    {
        // Arrange
        var viewEngine = CreateViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act & Assert
        ExceptionAssert.ThrowsArgumentNullOrEmpty(
            () => viewEngine.FindPage(context, pageName),
            "pageName");
    }

    [Fact]
    public void FindPage_UsesViewLocationExpander_ToExpandPaths()
    {
        // Arrange
        var routeValues = _controllerTestContext;
        var expectedSeeds = new[]
        {
                "/Views/{1}/{0}.cshtml",
                "/Views/Shared/{0}.cshtml"
            };

        var page = Mock.Of<IRazorPage>();
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
            .Setup(p => p.CreateFactory("expanded-path/bar-layout"))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();

        var expander = new Mock<IViewLocationExpander>();
        expander
            .Setup(e => e.PopulateValues(It.IsAny<ViewLocationExpanderContext>()))
            .Callback((ViewLocationExpanderContext c) =>
            {
                Assert.NotNull(c.ActionContext);
                c.Values["expander-key"] = expander.ToString();
            })
            .Verifiable();
        expander
            .Setup(e => e.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Returns((ViewLocationExpanderContext c, IEnumerable<string> seeds) =>
            {
                Assert.NotNull(c.ActionContext);
                Assert.Equal(expectedSeeds, seeds);

                Assert.Equal(expander.ToString(), c.Values["expander-key"]);

                return new[] { "expanded-path/bar-{0}" };
            })
            .Verifiable();

        var viewEngine = CreateViewEngine(
            pageFactory.Object,
            new[] { expander.Object });
        var context = GetActionContext(routeValues);

        // Act
        var result = viewEngine.FindPage(context, "layout");

        // Assert
        Assert.Equal("layout", result.Name);
        Assert.Same(page, result.Page);
        Assert.Null(result.SearchedLocations);
        pageFactory.Verify();
        expander.Verify();
    }

    [Fact]
    public void FindPage_UsesViewLocationExpander_ToExpandPaths_ForAreas()
    {
        // Arrange
        var routeValues = _areaTestContext;
        var expectedSeeds = new[]
        {
                "/Areas/{2}/Views/{1}/{0}.cshtml",
                "/Areas/{2}/Views/Shared/{0}.cshtml",
                "/Views/Shared/{0}.cshtml"
            };

        var page = Mock.Of<IRazorPage>();
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
            .Setup(p => p.CreateFactory("expanded-path/bar-layout"))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();

        var expander = new Mock<IViewLocationExpander>();
        expander
            .Setup(e => e.PopulateValues(It.IsAny<ViewLocationExpanderContext>()))
            .Callback((ViewLocationExpanderContext c) =>
            {
                Assert.NotNull(c.ActionContext);
                c.Values["expander-key"] = expander.ToString();
            })
            .Verifiable();
        expander
            .Setup(e => e.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Returns((ViewLocationExpanderContext c, IEnumerable<string> seeds) =>
            {
                Assert.NotNull(c.ActionContext);
                Assert.Equal(expectedSeeds, seeds);

                Assert.Equal(expander.ToString(), c.Values["expander-key"]);

                return new[] { "expanded-path/bar-{0}" };
            })
            .Verifiable();

        var viewEngine = CreateViewEngine(
            pageFactory.Object,
            new[] { expander.Object });
        var context = GetActionContext(routeValues);

        // Act
        var result = viewEngine.FindPage(context, "layout");

        // Assert
        Assert.Equal("layout", result.Name);
        Assert.Same(page, result.Page);
        Assert.Null(result.SearchedLocations);
        pageFactory.Verify();
        expander.Verify();
    }

    [Fact]
    public void FindPage_ReturnsSearchedLocationsIfPageCannotBeFound()
    {
        // Arrange
        var expected = new[]
        {
                "/Views/bar/layout.cshtml",
                "/Views/Shared/layout.cshtml",
            };

        var viewEngine = CreateViewEngine();
        var context = GetActionContext(_controllerTestContext);

        // Act
        var result = viewEngine.FindPage(context, "layout");

        // Assert
        Assert.Equal("layout", result.Name);
        Assert.Null(result.Page);
        Assert.Equal(expected, result.SearchedLocations);
    }

    [Fact]
    public void FindPage_SelectsActionCaseInsensitively()
    {
        // The ActionDescriptor contains "Foo" and the RouteData contains "foo"
        // which matches the case of the constructor thus searching in the appropriate location.
        // Arrange
        var routeValues = new Dictionary<string, object>
            {
                { "controller", "foo" }
            };
        var page = new Mock<IRazorPage>(MockBehavior.Strict);
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory
            .Setup(p => p.CreateFactory("/Views/Foo/details.cshtml"))
            .Returns(GetPageFactoryResult(() => page.Object))
            .Verifiable();

        var viewEngine = CreateViewEngine(pageFactory.Object);
        var routesInActionDescriptor = new Dictionary<string, string>()
            {
                { "controller", "Foo" }
            };

        var context = GetActionContextWithActionDescriptor(
            routeValues,
            routesInActionDescriptor);

        // Act
        var result = viewEngine.FindPage(context, "details");

        // Assert
        Assert.Equal("details", result.Name);
        Assert.Same(page.Object, result.Page);
        Assert.Null(result.SearchedLocations);
        pageFactory.Verify();
    }

    [Fact]
    public void FindPage_LooksForPages_UsingActionDescriptor_Controller()
    {
        // Arrange
        var expected = new[]
        {
                "/Views/bar/foo.cshtml",
                "/Views/Shared/foo.cshtml",
            };

        var routeValues = new Dictionary<string, object>
            {
                { "controller", "Bar" }
            };
        var routesInActionDescriptor = new Dictionary<string, string>()
            {
                { "controller", "bar" }
            };

        var viewEngine = CreateViewEngine();
        var context = GetActionContextWithActionDescriptor(
            routeValues,
            routesInActionDescriptor);

        // Act
        var result = viewEngine.FindPage(context, "foo");

        // Assert
        Assert.Equal("foo", result.Name);
        Assert.Null(result.Page);
        Assert.Equal(expected, result.SearchedLocations);
    }

    [Fact]
    public void FindPage_LooksForPages_UsingActionDescriptor_Areas()
    {
        // Arrange
        var expected = new[]
        {
                "/Areas/world/Views/bar/foo.cshtml",
                "/Areas/world/Views/Shared/foo.cshtml",
                "/Views/Shared/foo.cshtml"
            };

        var routeValues = new Dictionary<string, object>
            {
                { "controller", "Bar" },
                { "area", "World" }
            };
        var routesInActionDescriptor = new Dictionary<string, string>()
            {
                { "controller", "bar" },
                { "area", "world" }
            };

        var viewEngine = CreateViewEngine();
        var context = GetActionContextWithActionDescriptor(
            routeValues,
            routesInActionDescriptor);

        // Act
        var result = viewEngine.FindPage(context, "foo");

        // Assert
        Assert.Equal("foo", result.Name);
        Assert.Null(result.Page);
        Assert.Equal(expected, result.SearchedLocations);
    }

    [Fact]
    public void FindPage_LooksForPages_UsesRouteValuesAsFallback()
    {
        // Arrange
        var expected = new[]
        {
                "/Views/foo/bar.cshtml",
                "/Views/Shared/bar.cshtml",
            };

        var routeValues = new Dictionary<string, object>()
            {
                { "controller", "foo" }
            };

        var viewEngine = CreateViewEngine();
        var context = GetActionContextWithActionDescriptor(
            routeValues,
            new Dictionary<string, string>());

        // Act
        var result = viewEngine.FindPage(context, "bar");

        // Assert
        Assert.Equal("bar", result.Name);
        Assert.Null(result.Page);
        Assert.Equal(expected, result.SearchedLocations);
    }

    [Theory]
    [InlineData("/Test-View.cshtml")]
    [InlineData("~/Test-View.CSHTML")]
    [InlineData("/Home/Test-View.CSHTML")]
    [InlineData("~/Home/Test-View.cshtml")]
    [InlineData("~/SHARED/TEST-VIEW.CSHTML")]
    public void GetPage_UsesGivenPath_WithAppRelativePath(string pageName)
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory(pageName))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act
        var result = viewEngine.GetPage("~/Another/Place.cshtml", pagePath: pageName);

        // Assert
        Assert.Same(page, result.Page);
        Assert.Equal(pageName, result.Name);
        pageFactory.Verify();
    }

    [Theory]
    [InlineData("Test-View.cshtml")]
    [InlineData("Test-View.CSHTML")]
    [InlineData("PATH/TEST-VIEW.CSHTML")]
    [InlineData("Path1/Path2/Test-View.cshtml")]
    public void GetPage_ResolvesRelativeToCurrentPage_WithRelativePath(string pageName)
    {
        // Arrange
        var expectedPageName = $"/Home/{ pageName }";
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory(expectedPageName))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act
        var result = viewEngine.GetPage("/Home/Page.cshtml", pageName);

        // Assert
        Assert.Same(page, result.Page);
        Assert.Equal(pageName, result.Name);
        pageFactory.Verify();
    }

    [Theory]
    [InlineData("Test-View.cshtml")]
    [InlineData("Test-View.CSHTML")]
    [InlineData("PATH/TEST-VIEW.CSHTML")]
    [InlineData("Path1/Path2/Test-View.cshtml")]
    public void GetPage_ResolvesRelativeToAppRoot_WithRelativePath_IfNoPageExecuting(string pageName)
    {
        // Arrange
        var expectedPageName = $"/{ pageName }";
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        pageFactory
            .Setup(p => p.CreateFactory(expectedPageName))
            .Returns(GetPageFactoryResult(() => page))
            .Verifiable();
        var viewEngine = new TestableRazorViewEngine(
            pageFactory.Object,
            GetOptionsAccessor());

        // Act
        var result = viewEngine.GetPage(executingFilePath: null, pagePath: pageName);

        // Assert
        Assert.Same(page, result.Page);
        Assert.Equal(pageName, result.Name);
        pageFactory.Verify();
    }

    [Theory]
    [InlineData(null, null)]
    [InlineData(null, "")]
    [InlineData(null, "Page")]
    [InlineData(null, "Folder/Page")]
    [InlineData(null, "Folder1/Folder2/Page")]
    [InlineData("/Home/Index.cshtml", null)]
    [InlineData("/Home/Index.cshtml", "")]
    [InlineData("/Home/Index.cshtml", "Page")]
    [InlineData("/Home/Index.cshtml", "Folder/Page")]
    [InlineData("/Home/Index.cshtml", "Folder1/Folder2/Page")]
    public void GetAbsolutePath_ReturnsPagePathUnchanged_IfNotAPath(string executingFilePath, string pagePath)
    {
        // Arrange
        var viewEngine = CreateViewEngine();

        // Act
        var result = viewEngine.GetAbsolutePath(executingFilePath, pagePath);

        // Assert
        Assert.Same(pagePath, result);
    }

    [Theory]
    [InlineData("/Views/Home/Index.cshtml", "../Shared/_Partial.cshtml")]
    [InlineData("/Views/Home/Index.cshtml", "..\\Shared\\_Partial.cshtml")]
    [InlineData("/Areas/MyArea/Views/Home/Index.cshtml", "../../../../Views/Shared/_Partial.cshtml")]
    [InlineData("/Views/Accounts/Users.cshtml", "../Test/../Shared/_Partial.cshtml")]
    [InlineData("Views/Accounts/Users.cshtml", "./../Shared/./_Partial.cshtml")]
    public void GetAbsolutePath_ResolvesPathTraversals(string executingFilePath, string pagePath)
    {
        // Arrange
        var viewEngine = CreateViewEngine();

        // Act
        var result = viewEngine.GetAbsolutePath(executingFilePath, pagePath);

        // Assert
        Assert.Equal("/Views/Shared/_Partial.cshtml", result);
    }

    [Theory]
    [InlineData("../Shared/_Layout.cshtml")]
    [InlineData("Folder1/../Folder2/../../File.cshtml")]
    public void GetAbsolutePath_DoesNotResolvePathIfTraversalsEscapeTheRoot(string pagePath)
    {
        // Arrange
        var expected = '/' + pagePath;
        var viewEngine = CreateViewEngine();

        // Act
        var result = viewEngine.GetAbsolutePath("/Index.cshtml", pagePath);

        // Assert
        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData(null, "/Page")]
    [InlineData(null, "~/Folder/Page.cshtml")]
    [InlineData(null, "/Folder1/Folder2/Page.rzr")]
    [InlineData("/Home/Index.cshtml", "~/Page")]
    [InlineData("/Home/Index.cshtml", "/Folder/Page.cshtml")]
    [InlineData("/Home/Index.cshtml", "~/Folder1/Folder2/Page.rzr")]
    public void GetAbsolutePath_ReturnsPagePathUnchanged_IfAppRelative(string executingFilePath, string pagePath)
    {
        // Arrange
        var viewEngine = CreateViewEngine();

        // Act
        var result = viewEngine.GetAbsolutePath(executingFilePath, pagePath);

        // Assert
        Assert.Same(pagePath, result);
    }

    [Theory]
    [InlineData("Page.cshtml")]
    [InlineData("Folder/Page.cshtml")]
    [InlineData("../../Folder1/Folder2/Page.cshtml")]
    public void GetAbsolutePath_ResolvesRelativeToExecutingPage(string pagePath)
    {
        // Arrange
        var expectedPagePath = "/Home/" + pagePath;
        var viewEngine = CreateViewEngine();

        // Act
        var result = viewEngine.GetAbsolutePath("/Home/Page.cshtml", pagePath);

        // Assert
        Assert.Equal(expectedPagePath, result);
    }

    [Theory]
    [InlineData("Page.cshtml")]
    [InlineData("Folder/Page.cshtml")]
    [InlineData("../../Folder1/Folder2/Page.cshtml")]
    public void GetAbsolutePath_ResolvesRelativeToAppRoot_IfNoPageExecuting(string pagePath)
    {
        // Arrange
        var expectedPagePath = "/" + pagePath;
        var viewEngine = CreateViewEngine();

        // Act
        var result = viewEngine.GetAbsolutePath(executingFilePath: null, pagePath: pagePath);

        // Assert
        Assert.Equal(expectedPagePath, result);
    }

    [Fact]
    public void GetNormalizedRouteValue_ReturnsValueFromRouteValues()
    {
        // Arrange
        var key = "some-key";
        var actionDescriptor = new ActionDescriptor();
        actionDescriptor.RouteValues.Add(key, "Route-Value");

        var actionContext = new ActionContext
        {
            ActionDescriptor = actionDescriptor,
            RouteData = new RouteData()
        };

        actionContext.RouteData.Values[key] = "route-value";

        // Act
        var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);

        // Assert
        Assert.Equal("Route-Value", result);
    }

    [Fact]
    [ReplaceCulture("de-CH", "de-CH")]
    public void GetNormalizedRouteValue_UsesInvariantCulture()
    {
        // Arrange
        var key = "some-key";
        var actionDescriptor = new ActionDescriptor();
        actionDescriptor.RouteValues.Add(key, "Route-Value");

        var actionContext = new ActionContext
        {
            ActionDescriptor = actionDescriptor,
            RouteData = new RouteData()
        };

        actionContext.RouteData.Values[key] = new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7));

        // Act
        var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);

        // Assert
        Assert.Equal("10/31/2018 07:37:38 -07:00", result);
    }

    [Fact]
    public void GetNormalizedRouteValue_ReturnsRouteValue_IfValueDoesNotMatch()
    {
        // Arrange
        var key = "some-key";
        var actionDescriptor = new ActionDescriptor();
        actionDescriptor.RouteValues.Add(key, "different-value");

        var actionContext = new ActionContext
        {
            ActionDescriptor = actionDescriptor,
            RouteData = new RouteData()
        };

        actionContext.RouteData.Values[key] = "route-value";

        // Act
        var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);

        // Assert
        Assert.Equal("route-value", result);
    }

    [Fact]
    public void GetNormalizedRouteValue_ReturnsNonNormalizedValue_IfActionRouteValueIsNull()
    {
        // Arrange
        var key = "some-key";
        var actionDescriptor = new ActionDescriptor();
        actionDescriptor.RouteValues.Add(key, null);

        var actionContext = new ActionContext
        {
            ActionDescriptor = actionDescriptor,
            RouteData = new RouteData()
        };

        actionContext.RouteData.Values[key] = "route-value";

        // Act
        var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);

        // Assert
        Assert.Equal("route-value", result);
    }

    [Fact]
    public void GetNormalizedRouteValue_ConvertsRouteValueToString()
    {
        using (new CultureReplacer())
        {
            // Arrange
            var key = "some-key";
            var actionDescriptor = new ActionDescriptor
            {
                AttributeRouteInfo = new AttributeRouteInfo(),
            };

            var actionContext = new ActionContext
            {
                ActionDescriptor = actionDescriptor,
                RouteData = new RouteData()
            };

            actionContext.RouteData.Values[key] = 43;

            // Act
            var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);

            // Assert
            Assert.Equal("43", result);
        }
    }

    [Fact]
    public void GetViewLocationFormats_ForControllerWithoutArea_ReturnsDefaultSet()
    {
        // Arrange
        var expected = new string[] { "expected", };

        var viewEngine = new TestableRazorViewEngine(
            Mock.Of<IRazorPageFactoryProvider>(),
            GetOptionsAccessor(viewLocationFormats: expected));

        var context = new ViewLocationExpanderContext(
            new ActionContext(),
            "Index.cshtml",
            controllerName: "Home",
            areaName: null,
            pageName: "ignored",
            isMainPage: true);

        // Act
        var actual = viewEngine.GetViewLocationFormats(context);

        // Assert
        Assert.Equal(expected, actual);
    }

    [Fact]
    public void GetViewLocationFormats_ForControllerWithArea_ReturnsAreaSet()
    {
        // Arrange
        var expected = new string[] { "expected", };

        var viewEngine = new TestableRazorViewEngine(
            Mock.Of<IRazorPageFactoryProvider>(),
            GetOptionsAccessor(areaViewLocationFormats: expected));

        var context = new ViewLocationExpanderContext(
            new ActionContext(),
            "Index.cshtml",
            controllerName: "Home",
            areaName: "Admin",
            pageName: "ignored",
            isMainPage: true);

        // Act
        var actual = viewEngine.GetViewLocationFormats(context);

        // Assert
        Assert.Equal(expected, actual);
    }

    [Fact]
    public void GetViewLocationFormats_ForPage_ReturnsPageSet()
    {
        // Arrange
        var expected = new string[] { "expected", };

        var viewEngine = new TestableRazorViewEngine(
            Mock.Of<IRazorPageFactoryProvider>(),
            GetOptionsAccessor(pageViewLocationFormats: expected));

        var context = new ViewLocationExpanderContext(
            new ActionContext(),
            "Index.cshtml",
            controllerName: null,
            areaName: null,
            pageName: "/Some/Page",
            isMainPage: true);

        // Act
        var actual = viewEngine.GetViewLocationFormats(context);

        // Assert
        Assert.Equal(expected, actual);
    }

    // This isn't a real case we expect to hit in an app, just making sure we have a reasonable default
    // for a weird configuration. In this case we preserve what we did in 1.0.0.
    [Fact]
    public void GetViewLocationFormats_NoRouteValues_ReturnsDefaultSet()
    {
        // Arrange
        var expected = new string[] { "expected", };

        var viewEngine = new TestableRazorViewEngine(
            Mock.Of<IRazorPageFactoryProvider>(),
            GetOptionsAccessor(viewLocationFormats: expected));

        var context = new ViewLocationExpanderContext(
            new ActionContext(),
            "Index.cshtml",
            controllerName: null,
            areaName: null,
            pageName: null,
            isMainPage: true);

        // Act
        var actual = viewEngine.GetViewLocationFormats(context);

        // Assert
        Assert.Equal(expected, actual);
    }

    [Fact]
    public void ViewEngine_DoesNotSetPageValue_IfItIsNotSpecifiedInRouteValues()
    {
        // Arrange
        var routeValues = new Dictionary<string, object>
            {
                { "controller", "MyController" },
                { "action", "MyAction" }
            };

        var expected = new[] { "some-seed" };
        var expander = new Mock<IViewLocationExpander>();
        expander
            .Setup(e => e.PopulateValues(It.IsAny<ViewLocationExpanderContext>()))
            .Callback((ViewLocationExpanderContext c) =>
            {
                Assert.Equal("MyController", c.ControllerName);
                Assert.Null(c.PageName);
            })
            .Verifiable();

        expander
            .Setup(e => e.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Returns(expected);

        var viewEngine = CreateViewEngine(expanders: new[] { expander.Object });
        var context = GetActionContext(routeValues);

        // Act
        viewEngine.FindView(context, viewName: "Test-view", isMainPage: true);

        // Assert
        expander.Verify();
    }

    [Fact]
    public void ViewEngine_SetsPageValue_IfItIsSpecifiedInRouteValues()
    {
        // Arrange
        var routeValues = new Dictionary<string, object>
            {
                { "page", "MyPage" },
            };

        var expected = new[] { "some-seed" };
        var expander = new Mock<IViewLocationExpander>();
        expander
            .Setup(e => e.PopulateValues(It.IsAny<ViewLocationExpanderContext>()))
            .Callback((ViewLocationExpanderContext c) =>
            {
                Assert.Equal("MyPage", c.PageName);
            })
            .Verifiable();

        expander
            .Setup(e => e.ExpandViewLocations(
                It.IsAny<ViewLocationExpanderContext>(),
                It.IsAny<IEnumerable<string>>()))
            .Returns(expected);

        var viewEngine = CreateViewEngine(expanders: new[] { expander.Object });
        var context = GetActionContext(routeValues);
        context.ActionDescriptor.RouteValues["page"] = "MyPage";

        // Act
        viewEngine.FindView(context, viewName: "MyView", isMainPage: true);

        // Assert
        expander.Verify();
    }

    [Fact]
    public void FindView_ResolvesDirectoryTraversalsPriorToInvokingPageFactory()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory.Setup(p => p.CreateFactory("/Views/Shared/_Partial.cshtml"))
            .Returns(GetPageFactoryResult(() => Mock.Of<IRazorPage>()))
            .Verifiable();
        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(new Dictionary<string, object>());

        // Act
        var result = viewEngine.FindView(context, "../Shared/_Partial", isMainPage: false);

        // Assert
        pageFactory.Verify();
    }

    [Fact]
    public void FindPage_ResolvesDirectoryTraversalsPriorToInvokingPageFactory()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory.Setup(p => p.CreateFactory("/Views/Shared/_Partial.cshtml"))
            .Returns(GetPageFactoryResult(() => Mock.Of<IRazorPage>()))
            .Verifiable();
        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(new Dictionary<string, object>());

        // Act
        var result = viewEngine.FindPage(context, "../Shared/_Partial");

        // Assert
        pageFactory.Verify();
    }

    // Tests to verify fix for https://github.com/aspnet/Mvc/issues/6672
    // Without normalizing the path, the view engine would have attempted to lookup "/Views//MyView.cshtml"
    // which works for PhysicalFileProvider but fails for exact lookups performed during precompilation.
    // We normalize it to "/Views/MyView.cshtml" to avoid this discrepancy.
    [Fact]
    public void FindView_ResolvesNormalizesSlashesPriorToInvokingPageFactory()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory.Setup(p => p.CreateFactory("/Views/MyView.cshtml"))
            .Returns(GetPageFactoryResult(() => Mock.Of<IRazorPage>()))
            .Verifiable();
        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(new Dictionary<string, object>());

        // Act
        var result = viewEngine.FindView(context, "MyView", isMainPage: true);

        // Assert
        pageFactory.Verify();
    }

    [Fact]
    public void FindPage_ResolvesNormalizesSlashesPriorToInvokingPageFactory()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        pageFactory.Setup(p => p.CreateFactory("/Views/MyPage.cshtml"))
            .Returns(GetPageFactoryResult(() => Mock.Of<IRazorPage>()))
            .Verifiable();
        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(new Dictionary<string, object>());

        // Act
        var result = viewEngine.FindPage(context, "MyPage");

        // Assert
        pageFactory.Verify();
    }

    [Fact]
    public void FindView_Succeeds_AfterClearCache()
    {
        // Arrange
        var pageFactory = new Mock<IRazorPageFactoryProvider>();
        var page = Mock.Of<IRazorPage>();
        var hotReloadedPage = Mock.Of<IRazorPage>();

        pageFactory
            .Setup(p => p.CreateFactory("/Views/bar/Index.cshtml"))
            .Returns(GetPageFactoryResult(() => page));

        var viewEngine = CreateViewEngine(pageFactory.Object);
        var context = GetActionContext(_controllerTestContext);

        // Act - 1
        // First verify results are typically cached
        for (var i = 0; i < 3; i++)
        {

            var result = viewEngine.FindView(context, "Index", isMainPage: false);

            // Assert - 1
            Assert.True(result.Success);
            var view = Assert.IsType<RazorView>(result.View);
            Assert.Same(page, view.RazorPage);

            pageFactory.Verify(p => p.CreateFactory("/Views/bar/Index.cshtml"), Times.Once());
        }

        // Now verify that the page factory is re-invoked after cache clear
        viewEngine.ClearCache();
        pageFactory
            .Setup(p => p.CreateFactory("/Views/bar/Index.cshtml"))
            .Returns(GetPageFactoryResult(() => hotReloadedPage));

        {
            // Act - 2
            var result = viewEngine.FindView(context, "Index", isMainPage: false);

            // Assert - 2
            Assert.True(result.Success);
            var view = Assert.IsType<RazorView>(result.View);
            Assert.Same(hotReloadedPage, view.RazorPage);

            pageFactory.Verify(p => p.CreateFactory("/Views/bar/Index.cshtml"), Times.Exactly(2));
        }
    }

    // Return RazorViewEngine with a page factory provider that is always successful.
    private RazorViewEngine CreateSuccessfulViewEngine()
    {
        var pageFactory = new Mock<IRazorPageFactoryProvider>(MockBehavior.Strict);
        pageFactory
            .Setup(f => f.CreateFactory(It.IsAny<string>()))
            .Returns(GetPageFactoryResult(() => Mock.Of<IRazorPage>()));

        return CreateViewEngine(pageFactory.Object);
    }

    private static RazorPageFactoryResult GetPageFactoryResult(
        Func<IRazorPage> factory,
        IList<IChangeToken> changeTokens = null,
        string path = "/Views/Home/Index.cshtml")
    {
        var descriptor = new CompiledViewDescriptor
        {
            ExpirationTokens = changeTokens ?? Array.Empty<IChangeToken>(),
            RelativePath = path,
        };

        return new RazorPageFactoryResult(descriptor, factory);
    }

    private TestableRazorViewEngine CreateViewEngine(
        IRazorPageFactoryProvider pageFactory = null,
        IEnumerable<IViewLocationExpander> expanders = null)
    {
        pageFactory = pageFactory ?? Mock.Of<IRazorPageFactoryProvider>();
        return new TestableRazorViewEngine(pageFactory, GetOptionsAccessor(expanders));
    }

    private static IOptions<RazorViewEngineOptions> GetOptionsAccessor(
        IEnumerable<IViewLocationExpander> expanders = null,
        IEnumerable<string> viewLocationFormats = null,
        IEnumerable<string> areaViewLocationFormats = null,
        IEnumerable<string> pageViewLocationFormats = null)
    {
        var optionsSetup = new RazorViewEngineOptionsSetup();

        var options = new RazorViewEngineOptions();
        optionsSetup.Configure(options);
        options.PageViewLocationFormats.Add("/Views/Shared/{0}.cshtml");
        options.PageViewLocationFormats.Add("/Pages/Shared/{0}.cshtml");

        if (expanders != null)
        {
            foreach (var expander in expanders)
            {
                options.ViewLocationExpanders.Add(expander);
            }
        }

        if (viewLocationFormats != null)
        {
            options.ViewLocationFormats.Clear();

            foreach (var location in viewLocationFormats)
            {
                options.ViewLocationFormats.Add(location);
            }
        }

        if (areaViewLocationFormats != null)
        {
            options.AreaViewLocationFormats.Clear();

            foreach (var location in areaViewLocationFormats)
            {
                options.AreaViewLocationFormats.Add(location);
            }
        }

        if (pageViewLocationFormats != null)
        {
            options.PageViewLocationFormats.Clear();

            foreach (var location in pageViewLocationFormats)
            {
                options.PageViewLocationFormats.Add(location);
            }
        }

        var optionsAccessor = new Mock<IOptions<RazorViewEngineOptions>>();
        optionsAccessor
            .SetupGet(v => v.Value)
            .Returns(options);
        return optionsAccessor.Object;
    }

    private static ActionContext GetActionContext(IDictionary<string, object> routeValues)
    {
        var httpContext = new DefaultHttpContext();
        var routeData = new RouteData();
        foreach (var kvp in routeValues)
        {
            routeData.Values.Add(kvp.Key, kvp.Value);
        }

        var actionDescriptor = new ActionDescriptor();
        return new ActionContext(httpContext, routeData, actionDescriptor);
    }

    private static ActionContext GetActionContextWithActionDescriptor(
        IDictionary<string, object> routeValues,
        IDictionary<string, string> actionRouteValues)
    {
        var httpContext = new DefaultHttpContext();
        var routeData = new RouteData();
        foreach (var kvp in routeValues)
        {
            routeData.Values.Add(kvp.Key, kvp.Value);
        }

        var actionDescriptor = new ActionDescriptor();

        foreach (var kvp in actionRouteValues)
        {
            actionDescriptor.RouteValues.Add(kvp.Key, kvp.Value);
        }

        return new ActionContext(httpContext, routeData, actionDescriptor);
    }

    private class TestableRazorViewEngine : RazorViewEngine
    {
        public TestableRazorViewEngine(
            IRazorPageFactoryProvider pageFactory,
            IOptions<RazorViewEngineOptions> optionsAccessor)
            : base(pageFactory, Mock.Of<IRazorPageActivator>(), new HtmlTestEncoder(), optionsAccessor, NullLoggerFactory.Instance, new DiagnosticListener("Microsoft.AspNetCore.Mvc.Razor"))
        {
        }

        public IMemoryCache ViewLookupCachePublic => ViewLookupCache;
    }
}


text:
from __future__ import unicode_literals
import codecs
import os
import subprocess
import sys

class Task(object):
    """
    Documentation: https://docs.droppyapp.com/tasks/web-youtube-download
    """
    def __init__(self, input_dir, output_dir, **kwargs):
        # Get keyword arguments.
        youtubedl_exe = kwargs.get(str('youtubedl_executable'), '/usr/local/bin/youtube-dl')
        output_file_pattern = kwargs.get(str('output_file_pattern'), '%(title)s.%(ext)s')
        other_args = kwargs.get(str('other_args'), '')

        # Check for required external executable.
        if not os.path.isfile(youtubedl_exe):
            sys.exit('youtube-dl not found at "%s"' % youtubedl_exe)

        # Process files and directories.
        for item_name in os.listdir(input_dir):
            item_path = os.path.join(input_dir, item_name)

            if os.path.isfile(item_path):
                self.download_file(item_path, output_dir, youtubedl_exe, output_file_pattern, other_args)

            elif os.path.isdir(item_path):
                print('Skipping directory: %s' % item_path)

    @staticmethod
    def download_file(input_file, output_dir, youtubedl_exe, file_name_pattern, other_args):
        with codecs.open(input_file, encoding='utf-8', mode='r') as file_handler:
            for download_url in file_handler.readlines():

                command = youtubedl_exe
                command += ' --abort-on-error'
                command += ' --quiet'
                if len(other_args) > 0:
                    command += ' %s' % other_args
                command += ' --output "%s"' % (output_dir + os.sep + file_name_pattern)
                command += ' "%s"' % download_url

                print('Calling: %s' % command)

                exit_code = subprocess.call(command, shell=True)
                if exit_code > 0:
                    sys.exit(exit_code)

redpajama_set_name: RedPajamaGithub


text:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <name>Jodel</name>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.jodel</groupId>
    <artifactId>jodel-store</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>
    <scm>
        <connection>scm:git:git://github.com/saravanak/jodel.git</connection>
        <developerConnection>scm:git:git@github.com:saravanak/jodel.git</developerConnection>
        <url>http://github.com/saravanak/jodel</url>
    </scm>
    <dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-jsonSchema</artifactId>
            <version>2.4.0-rc3</version>
        </dependency>
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongo-java-driver</artifactId>
            <version>2.11.4</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.1.Final</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <reporting>
        <plugins>
            <!--            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>findbugs-maven-plugin</artifactId>
                <version>2.5.4</version>
            </plugin>-->
        </plugins>
    </reporting>

</project>


text:
package models

type PrivateMessage struct {
	Owner   uint
	Message string
}


text:
<?php
/**
 * Created by PhpStorm.
 * User: hert
 * Date: 03.03.14
 * Time: 18:03
 */

namespace Tixi\ApiBundle\Interfaces\Management;

/**
 * Class UserEditDTO
 * @package Tixi\ApiBundle\Interfaces\Management
 */
class UserEditDTO {
    public $id;
    public $role;
    public $username;
    public $email;
    public $password;
}


text:
title: 1.2.1.6. Generating QR Code for an Event
type: docs
weight: 50
url: /java/1-2-1-6-generating-qr-code-for-an-event/
---

## **How to generate QR Code for an Event?**
To generate a QR Code for a URL, please refer to the following steps:

1. Select the Type: **Event**
1. Fill out the content section: Event
1. Customize QR Code Settings (Optional)
1. Click **Generate Preview** button

That's It. You will see the generated QR Code under the preview section.
## **How it works?**
**Event Format**

BEGIN:VEVENT
SUMMARY:<Event Summary>
DTSTART:<Event Start Date Time>
DTEND:<Event End Date Time>
END:VEVENT
#### **API**
{{< highlight java >}}

 GET /qrcodegen/api/qrcode/generate?data=<SMSTO:Phone Number:MESSAGE>&foreColor=&bgColor=&ecc=&size=&format=

Sample Event Message

\------------------

BEGIN:VEVENT

SUMMARY:Independence Day Parades

DTSTART:20150323T090000

DTEND:20150323T110000

END:VEVENT

API Example:

\------------

http://localhost:8080/qrcodegen/api/qrcode/generate?data=BEGIN%3AVEVENT%0D%0ASUMMARY%3AIndependence Day Parades %0D%0ADTSTART%3A20150323T090000%0D%0ADTEND%3A20150323T110000%0D%0AEND%3AVEVENT&foreColor=&bgColor=&ecc=&size=&format=

{{< /highlight >}}

**Generated SMS QR Code**

|
![todo:image_alt_text](1-2-1-6-generating-qr-code-for-an-event_1.png)

|
| :- |
#### **Java Script**
JS code spinet to generate Event format from content input fields.

{{< highlight java >}}

  generateEvent : function(){

    	 var beginEvent = "BEGIN:VEVENT\r\n";

		 var endEvent = "END:VEVENT";

		 var eventDesc = "SUMMARY:" + this.$('.input-event-description').val() + "\r\n";

		 var eventStart = "DTSTART:" + this.$('.input-event-fromdate').val() + "\r\n";

		 var eventEnd = "DTEND:" + this.$('.input-event-todate').val() + "\r\n";

		 var generatedEvent = beginEvent + eventDesc + eventStart + eventEnd + endEvent;

		 return generatedEvent;

    },

{{< /highlight >}}
#### **Java**
**Core API Method - QRCodeManagementController.generateQRCode**

{{< highlight java >}}

 @RequestMapping(value = "generate", method = RequestMethod.GET,

    		produces = {MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE, MediaType.IMAGE_GIF_VALUE, MediaType_IMAGE_TIFF_VALUE, MediaType_IMAGE_BMP_VALUE})

    @ApiOperation(value = "Generate QR Code.")

    public ResponseEntity<byte[]>  generateQRCode(

    		@ApiParam( value = "data", name="data" , required = true)

    		@RequestParam("data") String data,

        HttpServletRequest request,HttpServletResponse response,

        @ApiParam( value = "A user-chosen password that can be used with password-based encryption (PBE) Algo PBEWITHMD5AND128BITAES-CBC-OPENSSL)", name="passKey", required=false) @RequestParam(required=false, value="passKey") String passKey,

        @ApiParam( value = "ForeColor e.g #000000 (Black - RGB(hex))", name="foreColor", required=false) @RequestParam(required=false, value="foreColor") String foreColor,

        @ApiParam( value = "BackgroundColor e.g #FFFFFF (White - RGB(hex))", name="bgColor", required=false) @RequestParam(required=false, value="bgColor") String bgColor,

        @ApiParam( value = "L|M|Q|H - Reed-Solomon error correctionCode Level(from low to high) default=Low", name="ecc", required=false) @RequestParam(required=false, value="ecc") String ecc,

        @ApiParam( value = "Image Size e.g #150x150", name="size", required=false) @RequestParam(required=false, value="size") String size,

        @ApiParam( value = "jpeg|tiff|gif|png|bmp - default=png", name="format", required=false) @RequestParam(required=false, value="format") String format,

        @ApiParam( value = "true|false default=false", name="download", required=false) @RequestParam(required=false, value="download") boolean download,

        @ApiIgnore @Value("#{request.getHeader('" +  ACCEPT_HEADER + "')}") String acceptHeaderValue) throws Exception {

{{< /highlight >}}


text:
var assert = require('chai').assert;

var arrayToObject = require(`${__dirname}/../../../src/steps/arrayToObject`);

describe('#arrayToObject', function () {

    it('should convert array to object', function () {

        var config = {
            from: 'a',
            to: 'b',
            byKey: 'id'
        };

        var data = {
            a: [{id: 1, login: 1}, {id: 2, login: 2}]
        };

        var result = {};

        arrayToObject(config, data, result);

        var valid = {
            b: {
                1: {id: 1, login: 1},
                2: {id: 2, login: 2}
            }
        };

        assert.deepEqual(valid, result);

    });

    it('should error on invalid config', function () {
        var data = {
            a: [{id: 1, login: 1}, {id: 2, login: 2}]
        };

        var result = {};

        assert.throws(x => arrayToObject({}, data, result), Error, 'invalid config fo step "arrayToObject"');
        assert.throws(x => arrayToObject({from: 'a'}, data, result), Error, 'invalid config fo step "arrayToObject"');
        assert.throws(x => arrayToObject({to: 'a'}, data, result), Error, 'invalid config fo step "arrayToObject"');
        assert.throws(x => arrayToObject({byKey: 'a'}, data, result), Error, 'invalid config fo step "arrayToObject"');
    });
});


text:
package edu.cs4730.blescannerdemo;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.core.content.ContextCompat;

import java.util.Map;

/**
 * helper class to make sure bluetooth is one and we have the correct permissions.
 */
public class Help_Fragment extends Fragment {

    String TAG = "HelpFragment";

    /**
     * This is the callback variable, for the button to launch the server or client fragment from the mainActivity.
     */
    private OnFragmentInteractionListener mListener;
    ActivityResultLauncher<Intent> bluetoothActivityResultLauncher;
    private String[] REQUIRED_PERMISSIONS;
    ActivityResultLauncher<String[]> rpl;

    /**
     * A callback interface that all activities containing this fragment must
     * implement. This mechanism allows activities to be notified of item
     * selections.
     */
    public interface OnFragmentInteractionListener {
        // Callback for when an item has been selected.
        void onButtonSelected(int id);
    }

    //bluetooth device and code to turn the device on if needed.
    BluetoothAdapter mBluetoothAdapter = null;
    Button btn_client;
    TextView logger;

    public Help_Fragment() {
        //for asking to turn on the bluetooth.
        bluetoothActivityResultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        // There are no request codes
                        Intent data = result.getData();
                        logthis("Bluetooth is on.");
                    } else {
                        logthis("Please turn the bluetooth on.");
                    }
                }
            });
        rpl = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(),
            new ActivityResultCallback<Map<String, Boolean>>() {
                @Override
                public void onActivityResult(Map<String, Boolean> isGranted) {
                    boolean granted = true;
                    for (Map.Entry<String, Boolean> x : isGranted.entrySet()) {
                        logthis(x.getKey() + " is " + x.getValue());
                        if (!x.getValue()) granted = false;
                    }
                    if (granted) startbt();
                }
            }
        );
    }

    //This code will check to see if there is a bluetooth device and
    //turn it on if is it turned off.
    public void startbt() {
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) {
            // Device does not support Bluetooth
            logthis("This device does not support bluetooth");
            return;
        }
        //make sure bluetooth is enabled.
        if (!mBluetoothAdapter.isEnabled()) {
            logthis("There is bluetooth, but turned off");
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            bluetoothActivityResultLauncher.launch(enableBtIntent);
        } else {
            logthis("The bluetooth is ready to use.");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View myView = inflater.inflate(R.layout.fragment_help, container, false);
        logger = (TextView) myView.findViewById(R.id.logger1);

        //setup the correct permissions needed, depending on which version. (31 changed the permissions.).
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
            REQUIRED_PERMISSIONS = new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT};
            logthis("Android 12+, we need scan and connect.");
        } else {
            REQUIRED_PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN};
            logthis("Android 11 or less, location and bluetooth permissions.");
        }
        //this allows us to check in the fragment instead of doing it all in the activity.

        btn_client = (Button) myView.findViewById(R.id.button2);
        btn_client.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mListener != null) //don't call if null, duh...
                    mListener.onButtonSelected(2);
            }
        });

        return myView;
    }

    @Override
    public void onResume() {
        super.onResume();
        if (!allPermissionsGranted())
            rpl.launch(REQUIRED_PERMISSIONS);
        else {
            logthis("All permissions have been granted already.");
            startbt();
        }
    }

    private boolean allPermissionsGranted() {
        for (String permission : REQUIRED_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(requireContext(), permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    /**
     * This is all for the callbacks
     */
    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        try {
            mListener = (OnFragmentInteractionListener) requireActivity();
        } catch (ClassCastException e) {
            throw new ClassCastException(requireActivity().toString()
                + " must implement OnFragmentInteractionListener");
        }

    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public void logthis(String msg) {
        logger.append(msg + "\n");
        Log.d(TAG, msg);
    }

}


text:
<title>s390 Directives - Using as</title>
<meta http-equiv="Content-Type" content="text/html">
<meta name="description" content="Using as">
<meta name="generator" content="makeinfo 4.13">
<link title="Top" rel="start" href="index.html#Top">
<link rel="up" href="S_002f390_002dDependent.html#S_002f390_002dDependent" title="S/390-Dependent">
<link rel="prev" href="s390-Syntax.html#s390-Syntax" title="s390 Syntax">
<link rel="next" href="s390-Floating-Point.html#s390-Floating-Point" title="s390 Floating Point">
<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">

<meta http-equiv="Content-Style-Type" content="text/css">

Next: s390 Floating Point,
Previous: s390 Syntax,
Up: S/390-Dependent

9.35.4 Assembler Directives

as for s390 supports all of the standard ELF
assembler directives as outlined in the main part of this document.
Some directives have been extended and there are some additional
directives, which are only available for the s390 as.

.insn
This directive permits the numeric representation of an instructions
and makes the assembler insert the operands according to one of the
instructions formats for ‘<samp>.insn</samp>’ (s390 Formats).
For example, the instruction ‘<samp>l %r1,24(%r15)</samp>’ could be written as
‘<samp>.insn rx,0x58000000,%r1,24(%r15)</samp>’.

.short
.long
.quad
This directive places one or more 16-bit (.short), 32-bit (.long), or
64-bit (.quad) values into the current section. If an ELF or TLS modifier
is used only the following expressions are allowed:
‘<samp>symbol@modifier + constant</samp>’,
‘<samp>symbol@modifier + label + constant</samp>’, and
‘<samp>symbol@modifier - label + constant</samp>’.
The following modifiers are available:

@got
@got12
The @got modifier can be used for .short, .long and .quad. The @got12
modifier is synonym to @got. The symbol is added to the GOT. The symbol
term is replaced with offset from the start of the GOT to the GOT slot for
the symbol.

@gotoff
The @gotoff modifier can be used for .short, .long and .quad. The symbol
term is replaced with the offset from the start of the GOT to the address
of the symbol.

@gotplt
The @gotplt modifier can be used for .long and .quad. A procedure linkage
table entry is generated for the symbol and a jump slot for the symbol
is added to the GOT. The symbol term is replaced with the offset from the
start of the GOT to the jump slot for the symbol.

@plt
The @plt modifier can be used for .long and .quad. A procedure linkage
table entry us generated for the symbol. The symbol term is replaced with
the address of the PLT entry for the symbol.

@pltoff
The @pltoff modifier can be used for .short, .long and .quad. The symbol
term is replaced with the offset from the start of the PLT to the address
of the symbol.

@tlsgd
@tlsldm
The @tlsgd and @tlsldm modifier can be used for .long and .quad. A
tls_index structure for the symbol is added to the GOT. The symbol term is
replaced with the offset from the start of the GOT to the tls_index structure.

@gotntpoff
@indntpoff
The @gotntpoff and @indntpoff modifier can be used for .long and .quad.
The symbol is added to the static TLS block and the negated offset to the
symbol in the static TLS block is added to the GOT. For @gotntpoff the
symbol term is replaced with the offset from the start of the GOT to the
GOT slot, for @indntpoff the symbol term is replaced with the address
of the GOT slot.

@dtpoff
The @dtpoff modifier can be used for .long and .quad. The symbol term
is replaced with the offset of the symbol relative to the start of the
TLS block it is contained in.

@ntpoff
The @ntpoff modifier can be used for .long and .quad. The symbol term
is replaced with the offset of the symbol relative to the TCB pointer.

For more information about the thread local storage modifiers see the
ELF extension documentation ‘<samp>ELF Handling For Thread-Local Storage</samp>’.

.ltorg
This directive causes the current contents of the literal pool to be
dumped to the current location (s390 Literal Pool Entries).

.machine string
This directive allows you to change the machine for which code is
generated.  string may be any of the -march= selection
options (without the -march=), push, or pop.
.machine push saves the currently selected cpu, which may be
restored with .machine pop.  Be aware that the cpu string has
to be put into double quotes in case it contains characters not
appropriate for identifiers.  So you have to write "z9-109"
instead of just z9-109.


text:
"""distutils

The main package for the Python Module Distribution Utilities.  Normally
used from a setup script as

   from distutils.core import setup

   setup (...)
"""

import sys

__version__ = sys.version[:sys.version.index(' ')]


text:
import React from 'react';

import { FieldConfigEditorProps, ThresholdsConfig, ThresholdsMode, ThresholdsFieldConfigSettings } from '@grafana/data';

import { ThresholdsEditor } from './ThresholdsEditor';

export class ThresholdsValueEditor extends React.PureComponent<
  FieldConfigEditorProps<ThresholdsConfig, ThresholdsFieldConfigSettings>
> {
  constructor(props: FieldConfigEditorProps<ThresholdsConfig, ThresholdsFieldConfigSettings>) {
    super(props);
  }

  render() {
    const { onChange } = this.props;
    let value = this.props.value;
    if (!value) {
      value = {
        mode: ThresholdsMode.Percentage,

        // Must be sorted by 'value', first value is always -Infinity
        steps: [
          // anything?
        ],
      };
    }

    return <ThresholdsEditor thresholds={value} onChange={onChange} />;
  }
}