Skip to content

feat: set Creation, LastAccess and LastWrite time for files #875

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -8,6 +8,14 @@ namespace System.IO.Abstractions.TestingHelpers
/// </summary>
public interface IMockFileDataAccessor : IFileSystem
{
/// <summary>
/// Adjust the times of the <paramref name="fileData"/>.
/// </summary>
/// <param name="fileData">The <see cref="MockFileData"/> for which the times should be adjusted.</param>
/// <param name="timeAdjustments">The adjustments to make on the <see cref="MockFileData"/>.</param>
/// <returns>The adjusted file.</returns>
MockFileData AdjustTimes(MockFileData fileData, TimeAdjustments timeAdjustments);

/// <summary>
/// Gets a file.
/// </summary>
12 changes: 6 additions & 6 deletions src/System.IO.Abstractions.TestingHelpers/MockDirectoryInfo.cs
Original file line number Diff line number Diff line change
@@ -62,15 +62,15 @@ public override FileAttributes Attributes
/// <inheritdoc />
public override DateTime CreationTime
{
get { return GetMockFileDataForRead().CreationTime.DateTime; }
get { return GetMockFileDataForRead().CreationTime.LocalDateTime; }
set { GetMockFileDataForWrite().CreationTime = value; }
}

/// <inheritdoc />
public override DateTime CreationTimeUtc
{
get { return GetMockFileDataForRead().CreationTime.UtcDateTime; }
set { GetMockFileDataForWrite().CreationTime = value.ToLocalTime(); }
set { GetMockFileDataForWrite().CreationTime = value; }
}

/// <inheritdoc />
@@ -114,29 +114,29 @@ public override string FullName
/// <inheritdoc />
public override DateTime LastAccessTime
{
get { return GetMockFileDataForRead().LastAccessTime.DateTime; }
get { return GetMockFileDataForRead().LastAccessTime.LocalDateTime; }
set { GetMockFileDataForWrite().LastAccessTime = value; }
}

/// <inheritdoc />
public override DateTime LastAccessTimeUtc
{
get { return GetMockFileDataForRead().LastAccessTime.UtcDateTime; }
set { GetMockFileDataForWrite().LastAccessTime = value.ToLocalTime(); }
set { GetMockFileDataForWrite().LastAccessTime = value; }
}

/// <inheritdoc />
public override DateTime LastWriteTime
{
get { return GetMockFileDataForRead().LastWriteTime.DateTime; }
get { return GetMockFileDataForRead().LastWriteTime.LocalDateTime; }
set { GetMockFileDataForWrite().LastWriteTime = value; }
}

/// <inheritdoc />
public override DateTime LastWriteTimeUtc
{
get { return GetMockFileDataForRead().LastWriteTime.UtcDateTime; }
set { GetMockFileDataForWrite().LastWriteTime = value.ToLocalTime(); }
set { GetMockFileDataForWrite().LastWriteTime = value; }
}

#if FEATURE_FILE_SYSTEM_INFO_LINK_TARGET
44 changes: 30 additions & 14 deletions src/System.IO.Abstractions.TestingHelpers/MockFile.cs
Original file line number Diff line number Diff line change
@@ -55,12 +55,13 @@ public override void AppendAllText(string path, string contents, Encoding encodi
if (!mockFileDataAccessor.FileExists(path))
{
VerifyDirectoryExists(path);
mockFileDataAccessor.AddFile(path, new MockFileData(contents, encoding));
mockFileDataAccessor.AddFile(path, mockFileDataAccessor.AdjustTimes(new MockFileData(contents, encoding), TimeAdjustments.All));
}
else
{
var file = mockFileDataAccessor.GetFile(path);
file.CheckFileAccess(path, FileAccess.Write);
mockFileDataAccessor.AdjustTimes(file, TimeAdjustments.LastAccessTime | TimeAdjustments.LastWriteTime);
var bytesToAppend = encoding.GetBytes(contents);
file.Contents = file.Contents.Concat(bytesToAppend).ToArray();
}
@@ -124,7 +125,7 @@ public override void Copy(string sourceFileName, string destFileName, bool overw
var sourceFileData = mockFileDataAccessor.GetFile(sourceFileName);
sourceFileData.CheckFileAccess(sourceFileName, FileAccess.Read);
var destFileData = new MockFileData(sourceFileData);
destFileData.CreationTime = destFileData.LastAccessTime = DateTime.Now;
mockFileDataAccessor.AdjustTimes(destFileData, TimeAdjustments.CreationTime | TimeAdjustments.LastAccessTime);
mockFileDataAccessor.AddFile(destFileName, destFileData);
}

@@ -151,6 +152,7 @@ private Stream CreateInternal(string path, FileAccess access, FileOptions option
VerifyDirectoryExists(path);

var mockFileData = new MockFileData(new byte[0]);
mockFileDataAccessor.AdjustTimes(mockFileData, TimeAdjustments.All);
mockFileDataAccessor.AddFile(path, mockFileData);
return OpenInternal(path, FileMode.Open, access, options);
}
@@ -188,7 +190,7 @@ public override IFileSystemInfo CreateSymbolicLink(string path, string pathToTar
var sourceFileData = mockFileDataAccessor.GetFile(pathToTarget);
sourceFileData.CheckFileAccess(pathToTarget, FileAccess.Read);
var destFileData = new MockFileData(new byte[0]);
destFileData.CreationTime = destFileData.LastAccessTime = DateTime.Now;
mockFileDataAccessor.AdjustTimes(destFileData, TimeAdjustments.CreationTime | TimeAdjustments.LastAccessTime);
destFileData.LinkTarget = pathToTarget;
mockFileDataAccessor.AddFile(path, destFileData);

@@ -436,7 +438,7 @@ public override void Move(string sourceFileName, string destFileName)
VerifyDirectoryExists(destFileName);

mockFileDataAccessor.RemoveFile(sourceFileName);
mockFileDataAccessor.AddFile(destFileName, new MockFileData(sourceFile));
mockFileDataAccessor.AddFile(destFileName, mockFileDataAccessor.AdjustTimes(new MockFileData(sourceFile), TimeAdjustments.LastAccessTime));
}

#if FEATURE_FILE_MOVE_WITH_OVERWRITE
@@ -480,9 +482,9 @@ public override void Move(string sourceFileName, string destFileName, bool overw
throw CommonExceptions.ProcessCannotAccessFileInUse();
}
VerifyDirectoryExists(destFileName);

mockFileDataAccessor.RemoveFile(sourceFileName);
mockFileDataAccessor.AddFile(destFileName, new MockFileData(sourceFile));
mockFileDataAccessor.AddFile(destFileName, mockFileDataAccessor.AdjustTimes(new MockFileData(sourceFile), TimeAdjustments.LastAccessTime));
}
#endif

@@ -539,6 +541,12 @@ private Stream OpenInternal(

var mockFileData = mockFileDataAccessor.GetFile(path);
mockFileData.CheckFileAccess(path, access);
var timeAdjustments = TimeAdjustments.LastAccessTime;
if (access.HasFlag(FileAccess.Write))
{
timeAdjustments |= TimeAdjustments.LastWriteTime;
}
mockFileDataAccessor.AdjustTimes(mockFileData, timeAdjustments);

return new MockFileStream(mockFileDataAccessor, path, mode, access, options);
}
@@ -578,7 +586,9 @@ public override byte[] ReadAllBytes(string path)
throw CommonExceptions.FileNotFound(path);
}
mockFileDataAccessor.GetFile(path).CheckFileAccess(path, FileAccess.Read);
return mockFileDataAccessor.GetFile(path).Contents.ToArray();
var fileData = mockFileDataAccessor.GetFile(path);
mockFileDataAccessor.AdjustTimes(fileData, TimeAdjustments.LastAccessTime);
return fileData.Contents.ToArray();
}

/// <inheritdoc />
@@ -590,10 +600,11 @@ public override string[] ReadAllLines(string path)
{
throw CommonExceptions.FileNotFound(path);
}
mockFileDataAccessor.GetFile(path).CheckFileAccess(path, FileAccess.Read);
var fileData = mockFileDataAccessor.GetFile(path);
fileData.CheckFileAccess(path, FileAccess.Read);
mockFileDataAccessor.AdjustTimes(fileData, TimeAdjustments.LastAccessTime);

return mockFileDataAccessor
.GetFile(path)
return fileData
.TextContents
.SplitLines();
}
@@ -613,9 +624,11 @@ public override string[] ReadAllLines(string path, Encoding encoding)
throw CommonExceptions.FileNotFound(path);
}

mockFileDataAccessor.GetFile(path).CheckFileAccess(path, FileAccess.Read);
var fileData = mockFileDataAccessor.GetFile(path);
fileData.CheckFileAccess(path, FileAccess.Read);
mockFileDataAccessor.AdjustTimes(fileData, TimeAdjustments.LastAccessTime);

using (var ms = new MemoryStream(mockFileDataAccessor.GetFile(path).Contents))
using (var ms = new MemoryStream(fileData.Contents))
using (var sr = new StreamReader(ms, encoding))
{
return sr.ReadToEnd().SplitLines();
@@ -713,6 +726,7 @@ public override void SetAccessControl(string path, FileSecurity fileSecurity)
}

var fileData = mockFileDataAccessor.GetFile(path);
mockFileDataAccessor.AdjustTimes(fileData, TimeAdjustments.LastAccessTime);
fileData.AccessControl = fileSecurity;
}

@@ -736,6 +750,7 @@ public override void SetAttributes(string path, FileAttributes fileAttributes)
}
else
{
mockFileDataAccessor.AdjustTimes(possibleFileData, TimeAdjustments.LastAccessTime);
possibleFileData.Attributes = fileAttributes;
}
}
@@ -824,7 +839,7 @@ public override void WriteAllBytes(string path, byte[] bytes)
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");
VerifyDirectoryExists(path);

mockFileDataAccessor.AddFile(path, new MockFileData(bytes.ToArray()));
mockFileDataAccessor.AddFile(path, mockFileDataAccessor.AdjustTimes(new MockFileData(bytes.ToArray()), TimeAdjustments.All));
}

/// <summary>
@@ -1094,7 +1109,7 @@ public override void WriteAllText(string path, string contents, Encoding encodin
VerifyDirectoryExists(path);

MockFileData data = contents == null ? new MockFileData(new byte[0]) : new MockFileData(contents, encoding);
mockFileDataAccessor.AddFile(path, data);
mockFileDataAccessor.AddFile(path, mockFileDataAccessor.AdjustTimes(data, TimeAdjustments.All));
}

internal static string ReadAllBytes(byte[] contents, Encoding encoding)
@@ -1110,6 +1125,7 @@ private string ReadAllTextInternal(string path, Encoding encoding)
{
var mockFileData = mockFileDataAccessor.GetFile(path);
mockFileData.CheckFileAccess(path, FileAccess.Read);
mockFileDataAccessor.AdjustTimes(mockFileData, TimeAdjustments.LastAccessTime);
return ReadAllBytes(mockFileData.Contents, encoding);
}

27 changes: 23 additions & 4 deletions src/System.IO.Abstractions.TestingHelpers/MockFileData.cs
Original file line number Diff line number Diff line change
@@ -49,7 +49,10 @@ public class MockFileData
/// </summary>
private MockFileData()
{
// empty
var now = DateTime.UtcNow;
LastWriteTime = now;
LastAccessTime = now;
CreationTime = now;
}

/// <summary>
@@ -78,6 +81,7 @@ public MockFileData(string textContents, Encoding encoding)
/// <param name="contents">The actual content.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="contents"/> is <see langword="null" />.</exception>
public MockFileData(byte[] contents)
: this()
{
Contents = contents ?? throw new ArgumentNullException(nameof(contents));
}
@@ -126,17 +130,32 @@ public string TextContents
/// <summary>
/// Gets or sets the date and time the <see cref="MockFileData"/> was created.
/// </summary>
public DateTimeOffset CreationTime { get; set; } = new DateTimeOffset(2010, 01, 02, 00, 00, 00, TimeSpan.FromHours(4));
public DateTimeOffset CreationTime
{
get { return creationTime; }
set{ creationTime = value.ToUniversalTime(); }
}
private DateTimeOffset creationTime;

/// <summary>
/// Gets or sets the date and time of the <see cref="MockFileData"/> was last accessed to.
/// </summary>
public DateTimeOffset LastAccessTime { get; set; } = new DateTimeOffset(2010, 02, 04, 00, 00, 00, TimeSpan.FromHours(4));
public DateTimeOffset LastAccessTime
{
get { return lastAccessTime; }
set { lastAccessTime = value.ToUniversalTime(); }
}
private DateTimeOffset lastAccessTime;

/// <summary>
/// Gets or sets the date and time of the <see cref="MockFileData"/> was last written to.
/// </summary>
public DateTimeOffset LastWriteTime { get; set; } = new DateTimeOffset(2010, 01, 04, 00, 00, 00, TimeSpan.FromHours(4));
public DateTimeOffset LastWriteTime
{
get { return lastWriteTime; }
set { lastWriteTime = value.ToUniversalTime(); }
}
private DateTimeOffset lastWriteTime;

#if FEATURE_FILE_SYSTEM_INFO_LINK_TARGET
/// <summary>
29 changes: 19 additions & 10 deletions src/System.IO.Abstractions.TestingHelpers/MockFileInfo.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Runtime.Versioning;
using System.Security.AccessControl;
using System.Text;

namespace System.IO.Abstractions.TestingHelpers
{
@@ -60,12 +59,12 @@ public override DateTime CreationTime
get
{
var mockFileData = GetMockFileDataForRead();
return mockFileData.CreationTime.DateTime;
return mockFileData.CreationTime.LocalDateTime;
}
set
{
var mockFileData = GetMockFileDataForWrite();
mockFileData.CreationTime = value;
mockFileData.CreationTime = AdjustUnspecifiedKind(value, DateTimeKind.Local);
}
}

@@ -80,7 +79,7 @@ public override DateTime CreationTimeUtc
set
{
var mockFileData = GetMockFileDataForWrite();
mockFileData.CreationTime = value.ToLocalTime();
mockFileData.CreationTime = AdjustUnspecifiedKind(value, DateTimeKind.Utc);
}
}

@@ -117,12 +116,12 @@ public override DateTime LastAccessTime
get
{
var mockFileData = GetMockFileDataForRead();
return mockFileData.LastAccessTime.DateTime;
return mockFileData.LastAccessTime.LocalDateTime;
}
set
{
var mockFileData = GetMockFileDataForWrite();
mockFileData.LastAccessTime = value;
mockFileData.LastAccessTime = AdjustUnspecifiedKind(value, DateTimeKind.Local);
}
}

@@ -137,7 +136,7 @@ public override DateTime LastAccessTimeUtc
set
{
var mockFileData = GetMockFileDataForWrite();
mockFileData.LastAccessTime = value;
mockFileData.LastAccessTime = AdjustUnspecifiedKind(value, DateTimeKind.Utc);
}
}

@@ -147,12 +146,12 @@ public override DateTime LastWriteTime
get
{
var mockFileData = GetMockFileDataForRead();
return mockFileData.LastWriteTime.DateTime;
return mockFileData.LastWriteTime.LocalDateTime;
}
set
{
var mockFileData = GetMockFileDataForWrite();
mockFileData.LastWriteTime = value;
mockFileData.LastWriteTime = AdjustUnspecifiedKind(value, DateTimeKind.Local);
}
}

@@ -167,7 +166,7 @@ public override DateTime LastWriteTimeUtc
set
{
var mockFileData = GetMockFileDataForWrite();
mockFileData.LastWriteTime = value.ToLocalTime();
mockFileData.LastWriteTime = AdjustUnspecifiedKind(value, DateTimeKind.Utc);
}
}

@@ -381,6 +380,16 @@ public override string ToString()
return originalPath;
}

private static DateTime AdjustUnspecifiedKind(DateTime time, DateTimeKind fallbackKind)
{
if (time.Kind == DateTimeKind.Unspecified)
{
return DateTime.SpecifyKind(time, fallbackKind);
}

return time;
}

private MockFileData GetMockFileDataForRead()
{
if (refreshOnNextRead)
Loading