a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
375 lines
17 KiB
C#
375 lines
17 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Web.Hosting;
|
|
using System.Web.WebPages.Scope;
|
|
using Moq;
|
|
using Xunit;
|
|
using Assert = Microsoft.TestCommon.AssertEx;
|
|
|
|
namespace Microsoft.Web.Helpers.Test
|
|
{
|
|
public class ThemesTest
|
|
{
|
|
[Fact]
|
|
public void Initialize_WithBadParams_Throws()
|
|
{
|
|
// Arrange
|
|
var mockVpp = new Mock<VirtualPathProvider>().Object;
|
|
var scope = new ScopeStorageDictionary();
|
|
|
|
// Act and Assert
|
|
Assert.ThrowsArgumentNullOrEmptyString(() => new ThemesImplementation(mockVpp, scope).Initialize(null, "foo"), "themeDirectory");
|
|
Assert.ThrowsArgumentNullOrEmptyString(() => new ThemesImplementation(mockVpp, scope).Initialize("", "foo"), "themeDirectory");
|
|
|
|
Assert.ThrowsArgumentNullOrEmptyString(() => new ThemesImplementation(mockVpp, scope).Initialize("~/folder", null), "defaultTheme");
|
|
Assert.ThrowsArgumentNullOrEmptyString(() => new ThemesImplementation(mockVpp, scope).Initialize("~/folder", ""), "defaultTheme");
|
|
}
|
|
|
|
[Fact]
|
|
public void CurrentThemeThrowsIfAssignedNullOrEmpty()
|
|
{
|
|
// Arrange
|
|
var mockVpp = new Mock<VirtualPathProvider>().Object;
|
|
var scope = new ScopeStorageDictionary();
|
|
var themesImpl = new ThemesImplementation(mockVpp, scope);
|
|
|
|
// Act and Assert
|
|
Assert.ThrowsArgumentNullOrEmptyString(() => { themesImpl.CurrentTheme = null; }, "value");
|
|
Assert.ThrowsArgumentNullOrEmptyString(() => { themesImpl.CurrentTheme = String.Empty; }, "value");
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokingPropertiesAndMethodsBeforeInitializationThrows()
|
|
{
|
|
// Arrange
|
|
var mockVpp = new Mock<VirtualPathProvider>().Object;
|
|
var scope = new ScopeStorageDictionary();
|
|
var themesImpl = new ThemesImplementation(mockVpp, scope);
|
|
|
|
// Act and Assert
|
|
Assert.Throws<InvalidOperationException>(() => themesImpl.CurrentTheme = "Foo",
|
|
@"You must call the ""Themes.Initialize"" method before you call any other method of the ""Themes"" class.");
|
|
|
|
Assert.Throws<InvalidOperationException>(() => { var x = themesImpl.CurrentTheme; },
|
|
@"You must call the ""Themes.Initialize"" method before you call any other method of the ""Themes"" class.");
|
|
|
|
Assert.Throws<InvalidOperationException>(() => { var x = themesImpl.AvailableThemes; },
|
|
@"You must call the ""Themes.Initialize"" method before you call any other method of the ""Themes"" class.");
|
|
|
|
Assert.Throws<InvalidOperationException>(() => { var x = themesImpl.DefaultTheme; },
|
|
@"You must call the ""Themes.Initialize"" method before you call any other method of the ""Themes"" class.");
|
|
|
|
Assert.Throws<InvalidOperationException>(() => { var x = themesImpl.GetResourcePath("baz"); },
|
|
@"You must call the ""Themes.Initialize"" method before you call any other method of the ""Themes"" class.");
|
|
|
|
Assert.Throws<InvalidOperationException>(() => { var x = themesImpl.GetResourcePath("baz", "some-file"); },
|
|
@"You must call the ""Themes.Initialize"" method before you call any other method of the ""Themes"" class.");
|
|
}
|
|
|
|
[Fact]
|
|
public void InitializeThrowsIfDefaultThemeDirectoryDoesNotExist()
|
|
{
|
|
// Arrange
|
|
var defaultTheme = "default-theme";
|
|
var themeDirectory = "theme-directory";
|
|
|
|
var scope = new ScopeStorageDictionary();
|
|
var themesImpl = new ThemesImplementation(GetVirtualPathProvider(themeDirectory, new Dir("not-default-theme")), scope);
|
|
|
|
// Act And Assert
|
|
Assert.ThrowsArgument(
|
|
() => themesImpl.Initialize(themeDirectory: themeDirectory, defaultTheme: defaultTheme),
|
|
"defaultTheme",
|
|
"Unknown theme 'default-theme'. Ensure that a directory labeled 'default-theme' exists under the theme directory.");
|
|
}
|
|
|
|
[Fact]
|
|
public void ThemesImplUsesScopeStorageToStoreProperties()
|
|
{
|
|
// Arrange
|
|
var defaultTheme = "default-theme";
|
|
var themeDirectory = "theme-directory";
|
|
|
|
var scope = new ScopeStorageDictionary();
|
|
var themesImpl = new ThemesImplementation(GetVirtualPathProvider(themeDirectory, new Dir(defaultTheme)), scope);
|
|
|
|
// Act
|
|
themesImpl.Initialize(themeDirectory: themeDirectory, defaultTheme: defaultTheme);
|
|
|
|
// Ensure Theme use scope storage to store properties
|
|
Assert.Equal(scope[ThemesImplementation.ThemesInitializedKey], true);
|
|
Assert.Equal(scope[ThemesImplementation.ThemeDirectoryKey], themeDirectory);
|
|
Assert.Equal(scope[ThemesImplementation.DefaultThemeKey], defaultTheme);
|
|
}
|
|
|
|
[Fact]
|
|
public void ThemesImplUsesDefaultThemeWhenNoCurrentThemeIsSpecified()
|
|
{
|
|
// Arrange
|
|
var defaultTheme = "default-theme";
|
|
var themeDirectory = "theme-directory";
|
|
|
|
var scope = new ScopeStorageDictionary();
|
|
var themesImpl = new ThemesImplementation(GetVirtualPathProvider(themeDirectory, new Dir(defaultTheme)), scope);
|
|
themesImpl.Initialize(themeDirectory, defaultTheme);
|
|
|
|
// Act and Assert
|
|
// CurrentTheme falls back to default theme when null
|
|
Assert.Equal(themesImpl.CurrentTheme, defaultTheme);
|
|
}
|
|
|
|
[Fact]
|
|
public void ThemesImplThrowsIfCurrentThemeIsInvalid()
|
|
{
|
|
// Arrange
|
|
var defaultTheme = "default-theme";
|
|
var themeDirectory = "theme-directory";
|
|
var themesImpl = new ThemesImplementation(GetVirtualPathProvider(themeDirectory, new Dir(defaultTheme), new Dir("not-a-random-value")), new ScopeStorageDictionary());
|
|
themesImpl.Initialize(themeDirectory, defaultTheme);
|
|
|
|
// Act and Assert
|
|
Assert.ThrowsArgument(() => themesImpl.CurrentTheme = "random-value",
|
|
"value",
|
|
"Unknown theme 'random-value'. Ensure that a directory labeled 'random-value' exists under the theme directory.");
|
|
}
|
|
|
|
[Fact]
|
|
public void ThemesImplUsesScopeStorageToStoreCurrentTheme()
|
|
{
|
|
// Arrange
|
|
var defaultTheme = "default-theme";
|
|
var themeDirectory = "theme-directory";
|
|
var currentThemeDir = "custom-theme-dir";
|
|
var scope = new ScopeStorageDictionary();
|
|
var themesImpl = new ThemesImplementation(GetVirtualPathProvider(themeDirectory, new Dir(defaultTheme), new Dir("custom-theme-dir")), scope);
|
|
|
|
// Act
|
|
themesImpl.Initialize(themeDirectory, defaultTheme);
|
|
themesImpl.CurrentTheme = currentThemeDir;
|
|
|
|
// Assert
|
|
Assert.Equal(scope[ThemesImplementation.CurrentThemeKey], currentThemeDir);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetResourcePathThrowsIfCurrentDirectoryIsNull()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("mobile"), new Dir(@"mobile", "wp7.css")));
|
|
themesImpl.Initialize("themes", "default");
|
|
|
|
// Act and Assert
|
|
Assert.ThrowsArgumentNull(() => themesImpl.GetResourcePath(folder: null, fileName: "wp7.css"), "folder");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetResourcePathThrowsIfFileNameIsNullOrEmpty()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("mobile"), new Dir(@"mobile", "wp7.css")));
|
|
themesImpl.Initialize("themes", "default");
|
|
|
|
// Act and Assert
|
|
Assert.ThrowsArgumentNullOrEmptyString(() => themesImpl.GetResourcePath(folder: String.Empty, fileName: null), "fileName");
|
|
Assert.ThrowsArgumentNullOrEmptyString(() => themesImpl.GetResourcePath(folder: String.Empty, fileName: String.Empty), "fileName");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetResourcePathReturnsItemFromThemeRootIfAvailable()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("mobile"), new Dir(@"mobile", "wp7.css")));
|
|
themesImpl.Initialize("themes", "default");
|
|
|
|
// Act
|
|
themesImpl.CurrentTheme = "mobile";
|
|
var themePath = themesImpl.GetResourcePath(fileName: "wp7.css");
|
|
|
|
// Assert
|
|
Assert.Equal(themePath, @"themes/mobile/wp7.css");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetResourcePathReturnsItemFromCurrentThemeDirectoryIfAvailable()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("mobile"), new Dir(@"mobile\styles", "wp7.css"), new Dir(@"default\styles", "main.css")));
|
|
themesImpl.Initialize("themes", "default");
|
|
|
|
// Act
|
|
themesImpl.CurrentTheme = "mobile";
|
|
var themePath = themesImpl.GetResourcePath(folder: "styles", fileName: "wp7.css");
|
|
|
|
// Assert
|
|
Assert.Equal(themePath, @"themes/mobile/styles/wp7.css");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetResourcePathReturnsItemFromDefaultThemeDirectoryIfNotFoundInCurrentThemeDirectory()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("mobile"), new Dir(@"mobile\styles", "wp7.css"), new Dir(@"default\styles", "main.css")));
|
|
themesImpl.Initialize("themes", "default");
|
|
|
|
// Act
|
|
themesImpl.CurrentTheme = "mobile";
|
|
var themePath = themesImpl.GetResourcePath(folder: "styles", fileName: "main.css");
|
|
|
|
// Assert
|
|
Assert.Equal(themePath, @"themes/default/styles/main.css");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetResourcePathReturnsNullIfDirectoryDoesNotExist()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("mobile"), new Dir(@"mobile\styles", "wp7.css"), new Dir(@"default\styles", "main.css")));
|
|
themesImpl.Initialize("themes", "default");
|
|
|
|
// Act
|
|
themesImpl.CurrentTheme = "mobile";
|
|
var themePath = themesImpl.GetResourcePath(folder: "does-not-exist", fileName: "main.css");
|
|
|
|
// Assert
|
|
Assert.Null(themePath);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetResourcePathReturnsNullIfItemNotFoundInCurrentAndDefaultThemeDirectories()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("mobile"), new Dir(@"mobile\styles", "wp7.css"), new Dir(@"default\styles", "main.css")));
|
|
themesImpl.Initialize("themes", "default");
|
|
|
|
// Act
|
|
themesImpl.CurrentTheme = "mobile";
|
|
var themePath = themesImpl.GetResourcePath(folder: "styles", fileName: "awesome-blinking-text.css");
|
|
|
|
// Assert
|
|
Assert.Null(themePath);
|
|
}
|
|
|
|
[Fact]
|
|
public void AvaliableThemesReturnsTopLevelDirectoriesUnderThemeDirectory()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("mobile"), new Dir("rotary-phone")));
|
|
// Act
|
|
themesImpl.Initialize("themes", "default");
|
|
var themes = themesImpl.AvailableThemes;
|
|
|
|
// Assert
|
|
Assert.Equal(3, themes.Count);
|
|
Assert.Equal(themes[0], "default");
|
|
Assert.Equal(themes[1], "mobile");
|
|
Assert.Equal(themes[2], "rotary-phone");
|
|
}
|
|
|
|
/// <remarks>
|
|
/// // folder structure:
|
|
/// // /root
|
|
/// // /foo
|
|
/// // /bar.cs
|
|
/// // testing that a file specified as foo/bar in folder root will return null
|
|
/// </remarks>
|
|
[Fact]
|
|
public void FileWithSlash_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("root"), new Dir(@"root\foo", "wp7.css"), new Dir(@"default\styles", "main.css")));
|
|
|
|
// Act
|
|
var actual = themesImpl.FindMatchingFile("root", "foo/bar.cs");
|
|
|
|
// Assert
|
|
Assert.Null(actual);
|
|
}
|
|
|
|
[Fact]
|
|
public void DirectoryWithNoFilesReturnsNull()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir("default"), new Dir("empty-dir")));
|
|
|
|
// Act
|
|
var actual = themesImpl.FindMatchingFile(@"themes\empty-dir", "main.css");
|
|
|
|
// Assert
|
|
Assert.Null(actual);
|
|
}
|
|
|
|
[Fact]
|
|
public void MatchingFiles_ReturnsCorrectFile()
|
|
{
|
|
// Arrange
|
|
var themesImpl = new ThemesImplementation(scopeStorage: new ScopeStorageDictionary(),
|
|
vpp: GetVirtualPathProvider("themes", new Dir(@"nomatchingfiles", "foo.cs")));
|
|
|
|
// Act
|
|
var bar = themesImpl.FindMatchingFile(@"themes\nomatchingfiles", "bar.cs");
|
|
var foo = themesImpl.FindMatchingFile(@"themes\nomatchingfiles", "foo.cs");
|
|
|
|
// Assert
|
|
Assert.Null(bar);
|
|
Assert.Equal(@"themes/nomatchingfiles/foo.cs", foo);
|
|
}
|
|
|
|
private static VirtualPathProvider GetVirtualPathProvider(string themeRoot, params Dir[] fileSystem)
|
|
{
|
|
var mockVpp = new Mock<VirtualPathProvider>();
|
|
var dirRoot = new Mock<VirtualDirectory>(themeRoot);
|
|
|
|
var themeDirectories = new List<VirtualDirectory>();
|
|
foreach (var directory in fileSystem)
|
|
{
|
|
var dir = new Mock<VirtualDirectory>(directory.Name);
|
|
var directoryPath = themeRoot + '\\' + directory.Name;
|
|
dir.SetupGet(d => d.Name).Returns(directory.Name);
|
|
mockVpp.Setup(c => c.GetDirectory(It.Is<string>(p => p.Equals(directoryPath, StringComparison.OrdinalIgnoreCase)))).Returns(dir.Object);
|
|
|
|
var fileList = new List<VirtualFile>();
|
|
foreach (var item in directory.Files)
|
|
{
|
|
var filePath = directoryPath + '\\' + item;
|
|
var file = new Mock<VirtualFile>(filePath);
|
|
file.SetupGet(f => f.Name).Returns(item);
|
|
fileList.Add(file.Object);
|
|
}
|
|
|
|
dir.SetupGet(c => c.Files).Returns(fileList);
|
|
themeDirectories.Add(dir.Object);
|
|
}
|
|
|
|
dirRoot.SetupGet(c => c.Directories).Returns(themeDirectories);
|
|
mockVpp.Setup(c => c.GetDirectory(themeRoot)).Returns(dirRoot.Object);
|
|
|
|
return mockVpp.Object;
|
|
}
|
|
|
|
private class Dir
|
|
{
|
|
public Dir(string name, params string[] files)
|
|
{
|
|
Name = name;
|
|
Files = files;
|
|
}
|
|
|
|
public string Name { get; private set; }
|
|
|
|
public IEnumerable<string> Files { get; private set; }
|
|
}
|
|
}
|
|
}
|