mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Add more unit test for IDependenciesFolder
--HG-- branch : dev
This commit is contained in:
@@ -1,57 +1,56 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
using Orchard.Tests.FileSystems.AppData;
|
||||
using Orchard.Tests.Stubs;
|
||||
|
||||
namespace Orchard.Tests.FileSystems.Dependencies {
|
||||
[TestFixture]
|
||||
public class DependenciesFolderTests {
|
||||
private string _tempFolder;
|
||||
private IAppDataFolder _appDataFolder;
|
||||
private IDependenciesFolder _dependenciesFolder;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
_tempFolder = Path.GetTempFileName();
|
||||
File.Delete(_tempFolder);
|
||||
|
||||
_appDataFolder = AppDataFolderTests.CreateAppDataFolder(_tempFolder);
|
||||
_dependenciesFolder = new DefaultDependenciesFolder(new Stubs.StubCacheManager(), _appDataFolder);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Term() {
|
||||
Directory.Delete(_tempFolder, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadDescriptorsShouldReturnEmptyList() {
|
||||
if (Directory.Exists(_tempFolder))
|
||||
Directory.Delete(_tempFolder, true);
|
||||
var e = _dependenciesFolder.LoadDescriptors();
|
||||
var clock = new StubClock();
|
||||
var appDataFolder = new StubAppDataFolder(clock);
|
||||
var dependenciesFolder = new DefaultDependenciesFolder(new StubCacheManager(), appDataFolder);
|
||||
|
||||
var e = dependenciesFolder.LoadDescriptors();
|
||||
Assert.That(e, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StoreDescriptorsShouldWork() {
|
||||
if (Directory.Exists(_tempFolder))
|
||||
Directory.Delete(_tempFolder, true);
|
||||
var clock = new StubClock();
|
||||
var appDataFolder = new StubAppDataFolder(clock);
|
||||
var dependenciesFolder = new DefaultDependenciesFolder(new StubCacheManager(), appDataFolder);
|
||||
|
||||
var d = new DependencyDescriptor {
|
||||
LoaderName = "test",
|
||||
Name = "name",
|
||||
VirtualPath = "~/bin"
|
||||
};
|
||||
|
||||
_dependenciesFolder.StoreDescriptors(new [] { d });
|
||||
var e = _dependenciesFolder.LoadDescriptors();
|
||||
dependenciesFolder.StoreDescriptors(new [] { d });
|
||||
var e = dependenciesFolder.LoadDescriptors();
|
||||
Assert.That(e, Has.Count.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StoreDescriptorsShouldNoOpIfNoChanges() {
|
||||
if (Directory.Exists(_tempFolder))
|
||||
Directory.Delete(_tempFolder, true);
|
||||
var clock = new StubClock();
|
||||
var appDataFolder = new StubAppDataFolder(clock);
|
||||
var dependenciesFolder = new DefaultDependenciesFolder(new StubCacheManager(), appDataFolder);
|
||||
|
||||
var d1 = new DependencyDescriptor {
|
||||
LoaderName = "test1",
|
||||
Name = "name1",
|
||||
@@ -64,13 +63,42 @@ namespace Orchard.Tests.FileSystems.Dependencies {
|
||||
VirtualPath = "~/bin2"
|
||||
};
|
||||
|
||||
_dependenciesFolder.StoreDescriptors(new[] { d1, d2 });
|
||||
var dateTime1 = File.GetLastWriteTimeUtc(Path.Combine(_tempFolder, "Dependencies", "Dependencies.xml"));
|
||||
dependenciesFolder.StoreDescriptors(new[] { d1, d2 });
|
||||
var dateTime1 = appDataFolder.GetLastWriteTimeUtc(Path.Combine("Dependencies", "Dependencies.xml"));
|
||||
clock.Advance(TimeSpan.FromMinutes(1));
|
||||
|
||||
_dependenciesFolder.StoreDescriptors(new[] { d2, d1 });
|
||||
var dateTime2 = File.GetLastWriteTimeUtc(Path.Combine(_tempFolder, "Dependencies", "Dependencies.xml"));
|
||||
dependenciesFolder.StoreDescriptors(new[] { d2, d1 });
|
||||
var dateTime2 = appDataFolder.GetLastWriteTimeUtc(Path.Combine("Dependencies", "Dependencies.xml"));
|
||||
Assert.That(dateTime1, Is.EqualTo(dateTime2));
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StoreDescriptorsShouldStoreIfChanges() {
|
||||
var clock = new StubClock();
|
||||
var appDataFolder = new StubAppDataFolder(clock);
|
||||
var dependenciesFolder = new DefaultDependenciesFolder(new StubCacheManager(), appDataFolder);
|
||||
|
||||
var d1 = new DependencyDescriptor {
|
||||
LoaderName = "test1",
|
||||
Name = "name1",
|
||||
VirtualPath = "~/bin1"
|
||||
};
|
||||
|
||||
var d2 = new DependencyDescriptor {
|
||||
LoaderName = "test2",
|
||||
Name = "name2",
|
||||
VirtualPath = "~/bin2"
|
||||
};
|
||||
|
||||
dependenciesFolder.StoreDescriptors(new[] { d1, d2 });
|
||||
var dateTime1 = appDataFolder.GetLastWriteTimeUtc(Path.Combine("Dependencies", "Dependencies.xml"));
|
||||
clock.Advance(TimeSpan.FromMinutes(1));
|
||||
|
||||
d1.LoaderName = "bar";
|
||||
|
||||
dependenciesFolder.StoreDescriptors(new[] { d2, d1 });
|
||||
var dateTime2 = appDataFolder.GetLastWriteTimeUtc(Path.Combine("Dependencies", "Dependencies.xml"));
|
||||
Assert.That(dateTime1 + TimeSpan.FromMinutes(1), Is.EqualTo(dateTime2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -201,6 +201,8 @@
|
||||
<Compile Include="Localization\CultureManagerTests.cs" />
|
||||
<Compile Include="Mvc\Routes\ShellRouteTests.cs" />
|
||||
<Compile Include="Mvc\Routes\UrlPrefixTests.cs" />
|
||||
<Compile Include="Stubs\StubFileSystem.cs" />
|
||||
<Compile Include="Stubs\StubAppDataFolder.cs" />
|
||||
<Compile Include="Stubs\StubVirtualPathMonitor.cs" />
|
||||
<Compile Include="Stubs\StubCacheManager.cs" />
|
||||
<Compile Include="Stubs\StubWebSiteFolder.cs" />
|
||||
|
77
src/Orchard.Tests/Stubs/StubAppDataFolder.cs
Normal file
77
src/Orchard.Tests/Stubs/StubAppDataFolder.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Orchard.Caching;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Tests.Stubs {
|
||||
public class StubAppDataFolder : IAppDataFolder {
|
||||
private readonly IClock _clock;
|
||||
private readonly StubFileSystem _stubFileSystem;
|
||||
|
||||
public StubAppDataFolder(IClock clock) {
|
||||
_clock = clock;
|
||||
_stubFileSystem = new StubFileSystem(_clock);
|
||||
}
|
||||
|
||||
public StubFileSystem StubFileSystem {
|
||||
get { return _stubFileSystem; }
|
||||
}
|
||||
|
||||
public IEnumerable<string> ListFiles(string path) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerable<string> ListDirectories(string path) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool FileExists(string path) {
|
||||
return _stubFileSystem.GetFileEntry(path) != null;
|
||||
}
|
||||
|
||||
public string Combine(params string[] paths) {
|
||||
return Path.Combine(paths).Replace(Path.DirectorySeparatorChar, '/');
|
||||
}
|
||||
|
||||
public void CreateFile(string path, string content) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Stream CreateFile(string path) {
|
||||
return _stubFileSystem.CreateFile(path);
|
||||
}
|
||||
|
||||
public string ReadFile(string path) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Stream OpenFile(string path) {
|
||||
return _stubFileSystem.OpenFile(path);
|
||||
}
|
||||
|
||||
public void DeleteFile(string path) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void CreateDirectory(string path) {
|
||||
var entry = _stubFileSystem.CreateDirectoryEntry(path);
|
||||
}
|
||||
|
||||
public IVolatileToken WhenPathChanges(string path) {
|
||||
return _stubFileSystem.WhenPathChanges(path);
|
||||
}
|
||||
|
||||
public string MapPath(string path) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public DateTime GetLastWriteTimeUtc(string path) {
|
||||
var entry = _stubFileSystem.GetFileEntry(path);
|
||||
if (entry == null)
|
||||
throw new InvalidOperationException();
|
||||
return entry.LastWriteTime;
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,13 +3,17 @@ using Orchard.Caching;
|
||||
|
||||
namespace Orchard.Tests.Stubs {
|
||||
public class StubCacheManager : ICacheManager {
|
||||
private readonly ICacheManager _defaultCacheManager;
|
||||
|
||||
public StubCacheManager() {
|
||||
_defaultCacheManager = new DefaultCacheManager(this.GetType(), new DefaultCacheHolder());
|
||||
}
|
||||
public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
|
||||
var cache = new Cache<TKey, TResult>();
|
||||
return cache.Get(key, acquire);
|
||||
return _defaultCacheManager.Get(key, acquire);
|
||||
}
|
||||
|
||||
public ICache<TKey, TResult> GetCache<TKey, TResult>() {
|
||||
throw new NotImplementedException();
|
||||
return _defaultCacheManager.GetCache<TKey, TResult>();
|
||||
}
|
||||
}
|
||||
}
|
364
src/Orchard.Tests/Stubs/StubFileSystem.cs
Normal file
364
src/Orchard.Tests/Stubs/StubFileSystem.cs
Normal file
@@ -0,0 +1,364 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Tests.Stubs {
|
||||
public class StubFileSystem {
|
||||
public class Entry {
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class DirectoryEntry : Entry {
|
||||
private readonly IClock _clock;
|
||||
|
||||
public DirectoryEntry(IClock clock) {
|
||||
_clock = clock;
|
||||
Entries = new List<Entry>();
|
||||
}
|
||||
|
||||
public IList<Entry> Entries { get; private set; }
|
||||
|
||||
public Entry GetEntry(string name) {
|
||||
if (string.IsNullOrEmpty(name))
|
||||
throw new ArgumentException();
|
||||
|
||||
if (name.Contains(Path.DirectorySeparatorChar) || name.Contains(Path.AltDirectorySeparatorChar))
|
||||
throw new ArgumentException();
|
||||
|
||||
return Entries.FirstOrDefault(e => StringComparer.OrdinalIgnoreCase.Equals(e.Name, name));
|
||||
}
|
||||
|
||||
public DirectoryEntry CreateDirectory(string name) {
|
||||
var entry = GetEntry(name);
|
||||
|
||||
if (entry == null) {
|
||||
entry = new DirectoryEntry(_clock) { Name = name };
|
||||
this.Entries.Add(entry);
|
||||
}
|
||||
|
||||
if (!(entry is DirectoryEntry)) {
|
||||
throw new InvalidOperationException(string.Format("Can't create directory \"{0}\": not a directory.", name));
|
||||
}
|
||||
|
||||
return (DirectoryEntry)entry;
|
||||
}
|
||||
|
||||
public FileEntry CreateFile(string name) {
|
||||
var entry = GetEntry(name);
|
||||
|
||||
if (entry == null) {
|
||||
entry = new FileEntry (_clock) { Name = name };
|
||||
this.Entries.Add(entry);
|
||||
}
|
||||
|
||||
if (!(entry is FileEntry)) {
|
||||
throw new InvalidOperationException(string.Format("Can't create file \"{0}\": not a file.", name));
|
||||
}
|
||||
|
||||
return (FileEntry)entry;
|
||||
}
|
||||
}
|
||||
|
||||
public class FileEntry : Entry {
|
||||
private readonly IClock _clock;
|
||||
|
||||
public FileEntry(IClock clock) {
|
||||
_clock = clock;
|
||||
LastWriteTime = _clock.UtcNow;
|
||||
Content = new List<byte>();
|
||||
}
|
||||
|
||||
public List<byte> Content { get; private set; }
|
||||
public DateTime LastWriteTime { get; set; }
|
||||
}
|
||||
|
||||
public class Token : IVolatileToken {
|
||||
private readonly StubFileSystem _stubFileSystem;
|
||||
private readonly string _path;
|
||||
private bool _isCurrent;
|
||||
|
||||
public Token(StubFileSystem stubFileSystem, string path) {
|
||||
_stubFileSystem = stubFileSystem;
|
||||
_path = path;
|
||||
_isCurrent = true;
|
||||
}
|
||||
|
||||
public bool IsCurrent { get { return _isCurrent; } }
|
||||
|
||||
public void OnChange() {
|
||||
_isCurrent = false;
|
||||
_stubFileSystem.DetachToken(_path);
|
||||
}
|
||||
}
|
||||
|
||||
public class FileEntryWriteStream : Stream {
|
||||
private readonly Token _token;
|
||||
private readonly FileEntry _entry;
|
||||
private readonly IClock _clock;
|
||||
private long _position;
|
||||
|
||||
public FileEntryWriteStream(Token token, StubFileSystem.FileEntry entry, IClock clock) {
|
||||
_token = token;
|
||||
_entry = entry;
|
||||
_clock = clock;
|
||||
}
|
||||
|
||||
public override void Flush() {
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public class ArrayWrapper<T> : ICollection<T> {
|
||||
private readonly T[] _buffer;
|
||||
private readonly int _offset;
|
||||
private readonly int _count;
|
||||
|
||||
public ArrayWrapper(T[] buffer, int offset, int count) {
|
||||
_buffer = buffer;
|
||||
_offset = offset;
|
||||
_count = count;
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator() {
|
||||
for (int i = _offset; i < _count; i++)
|
||||
yield return _buffer[i];
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add(T item) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Contains(T item) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex) {
|
||||
Array.Copy(_buffer, _offset, array, arrayIndex, _count);
|
||||
}
|
||||
|
||||
public bool Remove(T item) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get { return _count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly {
|
||||
get { return true; }
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
var wrapper = new ArrayWrapper<byte>(buffer, offset, count);
|
||||
_entry.Content.AddRange(wrapper);
|
||||
|
||||
_entry.LastWriteTime = _clock.UtcNow;
|
||||
if (_token != null)
|
||||
_token.OnChange();
|
||||
_position += count;
|
||||
}
|
||||
|
||||
public override bool CanRead {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanSeek {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override long Length {
|
||||
get { return _entry.Content.Count; }
|
||||
}
|
||||
|
||||
public override long Position {
|
||||
get { return _position; }
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
}
|
||||
|
||||
public class FileEntryReadStream : Stream {
|
||||
private readonly FileEntry _entry;
|
||||
private readonly IClock _clock;
|
||||
private int _position;
|
||||
|
||||
public FileEntryReadStream(FileEntry entry, IClock clock) {
|
||||
_entry = entry;
|
||||
_clock = clock;
|
||||
}
|
||||
|
||||
public override void Flush() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) {
|
||||
switch (origin) {
|
||||
case SeekOrigin.Begin:
|
||||
_position = (int)offset;
|
||||
break;
|
||||
case SeekOrigin.Current:
|
||||
_position += (int) offset;
|
||||
break;
|
||||
case SeekOrigin.End:
|
||||
_position = _entry.Content.Count - (int) offset;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("origin");
|
||||
}
|
||||
return _position;
|
||||
}
|
||||
|
||||
public override void SetLength(long value) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) {
|
||||
int remaingCount = _entry.Content.Count - _position;
|
||||
count = Math.Min(count, remaingCount);
|
||||
|
||||
_entry.Content.CopyTo(_position, buffer, offset, count);
|
||||
|
||||
_position += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool CanRead {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanSeek {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanWrite {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override long Length {
|
||||
get { return _entry.Content.Count; }
|
||||
}
|
||||
|
||||
public override long Position {
|
||||
get { return _position; }
|
||||
set { _position = (int) value; }
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IClock _clock;
|
||||
private readonly DirectoryEntry _root;
|
||||
private readonly Dictionary<string, Weak<Token>> _tokens;
|
||||
|
||||
public StubFileSystem(IClock clock) {
|
||||
_clock = clock;
|
||||
_root = new DirectoryEntry(_clock);
|
||||
_tokens = new Dictionary<string, Weak<Token>>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private DirectoryEntry GetDirectoryEntry(string path) {
|
||||
path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
var current = _root;
|
||||
foreach (var name in path.Split(Path.DirectorySeparatorChar)) {
|
||||
current = current.GetEntry(name) as StubFileSystem.DirectoryEntry;
|
||||
if (current == null)
|
||||
break;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
public DirectoryEntry CreateDirectoryEntry(string path) {
|
||||
path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
var current = _root;
|
||||
foreach (var name in path.Split(Path.DirectorySeparatorChar)) {
|
||||
current = current.CreateDirectory(name);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
public FileEntry GetFileEntry(string path) {
|
||||
var directoryName = Path.GetDirectoryName(path);
|
||||
var fileName = Path.GetFileName(path);
|
||||
|
||||
var directory = GetDirectoryEntry(directoryName);
|
||||
if (directory == null)
|
||||
return null;
|
||||
|
||||
return directory.GetEntry(fileName) as StubFileSystem.FileEntry;
|
||||
}
|
||||
|
||||
public FileEntry CreateFileEntry(string path) {
|
||||
var directoryName = Path.GetDirectoryName(path);
|
||||
var fileName = Path.GetFileName(path);
|
||||
|
||||
return CreateDirectoryEntry(directoryName).CreateFile(fileName);
|
||||
}
|
||||
|
||||
public IVolatileToken WhenPathChanges(string path) {
|
||||
Token token = GetToken(path);
|
||||
|
||||
if (token == null) {
|
||||
token = new Token(this, path);
|
||||
_tokens.Add(path, new Weak<Token>(token));
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
private Token GetToken(string path) {
|
||||
Token token = null;
|
||||
Weak<Token> weakRef;
|
||||
if (_tokens.TryGetValue(path, out weakRef))
|
||||
token = weakRef.Target;
|
||||
return token;
|
||||
}
|
||||
|
||||
private void DetachToken(string path) {
|
||||
_tokens.Remove(path);
|
||||
}
|
||||
|
||||
public Stream CreateFile(string path) {
|
||||
var entry = CreateFileEntry(path);
|
||||
return new FileEntryWriteStream(GetToken(path), entry, _clock);
|
||||
}
|
||||
|
||||
public Stream OpenFile(string path) {
|
||||
var entry = GetFileEntry(path);
|
||||
if (entry == null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
return new FileEntryReadStream(entry, _clock);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user