-
Notifications
You must be signed in to change notification settings - Fork 261
/
Copy pathMockFileData.cs
245 lines (217 loc) · 9.02 KB
/
MockFileData.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
using System.Linq;
using System.Runtime.Versioning;
using System.Security.AccessControl;
using System.Text;
namespace System.IO.Abstractions.TestingHelpers;
/// <summary>
/// The class represents the associated data of a file.
/// </summary>
#if FEATURE_SERIALIZABLE
[Serializable]
#endif
public class MockFileData
{
/// <summary>
/// The default encoding.
/// </summary>
public static readonly Encoding DefaultEncoding = new UTF8Encoding(false, true);
/// <summary>
/// The null object. It represents the data of a non-existing file or directory.
/// </summary>
internal static readonly MockFileData NullObject = new MockFileData(string.Empty)
{
LastWriteTime = new DateTime(1601, 01, 01, 00, 00, 00, DateTimeKind.Utc),
LastAccessTime = new DateTime(1601, 01, 01, 00, 00, 00, DateTimeKind.Utc),
CreationTime = new DateTime(1601, 01, 01, 00, 00, 00, DateTimeKind.Utc),
Attributes = (FileAttributes)(-1),
};
/// <summary>
/// Gets the default date time offset.
/// E.g. for not existing files.
/// </summary>
public static readonly DateTimeOffset DefaultDateTimeOffset = new DateTime(1601, 01, 01, 00, 00, 00, DateTimeKind.Utc);
/// <summary>
/// The access control of the <see cref="MockFileData"/>.
/// </summary>
#if FEATURE_SERIALIZABLE
[NonSerialized]
#endif
private FileSecurity accessControl;
/// <summary>
/// Gets a value indicating whether the <see cref="MockFileData"/> is a directory or not.
/// </summary>
public bool IsDirectory { get { return Attributes.HasFlag(FileAttributes.Directory); } }
/// <summary>
/// Initializes a new instance of the <see cref="MockFileData"/> class with an empty content.
/// </summary>
private MockFileData()
{
var now = DateTime.UtcNow;
LastWriteTime = now;
LastAccessTime = now;
CreationTime = now;
}
/// <summary>
/// Initializes a new instance of the <see cref="MockFileData"/> class with the content of <paramref name="textContents"/> using the encoding of <see cref="DefaultEncoding"/>.
/// </summary>
/// <param name="textContents">The textual content encoded into bytes with <see cref="DefaultEncoding"/>.</param>
public MockFileData(string textContents)
: this(DefaultEncoding.GetBytes(textContents))
{ }
/// <summary>
/// Initializes a new instance of the <see cref="MockFileData"/> class with the content of <paramref name="textContents"/> using the encoding of <paramref name="encoding"/>.
/// </summary>
/// <param name="textContents">The textual content.</param>
/// <param name="encoding">The specific encoding used the encode the text.</param>
/// <remarks>The constructor respect the BOM of <paramref name="encoding"/>.</remarks>
public MockFileData(string textContents, Encoding encoding)
: this()
{
Contents = encoding.GetPreamble().Concat(encoding.GetBytes(textContents)).ToArray();
}
/// <summary>
/// Initializes a new instance of the <see cref="MockFileData"/> class with the content of <paramref name="contents"/>.
/// </summary>
/// <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));
}
/// <summary>
/// Initializes a new instance of the <see cref="MockFileData"/> class by copying the given <see cref="MockFileData"/>.
/// </summary>
/// <param name="template">The template instance.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="template"/> is <see langword="null" />.</exception>
public MockFileData(MockFileData template)
{
if (template == null)
{
throw new ArgumentNullException(nameof(template));
}
accessControl = template.accessControl;
Attributes = template.Attributes;
Contents = template.Contents.ToArray();
CreationTime = template.CreationTime;
LastAccessTime = template.LastAccessTime;
LastWriteTime = template.LastWriteTime;
#if FEATURE_FILE_SYSTEM_INFO_LINK_TARGET
LinkTarget = template.LinkTarget;
#endif
}
/// <summary>
/// Gets or sets the byte contents of the <see cref="MockFileData"/>.
/// </summary>
public byte[] Contents { get; set; }
/// <summary>
/// Gets or sets the file version info of the <see cref="MockFileData"/>
/// </summary>
public IFileVersionInfo FileVersionInfo { get; set; }
/// <summary>
/// Gets or sets the string contents of the <see cref="MockFileData"/>.
/// </summary>
/// <remarks>
/// The setter uses the <see cref="DefaultEncoding"/> using this can scramble the actual contents.
/// </remarks>
public string TextContents
{
get { return MockFile.ReadAllBytes(Contents, DefaultEncoding); }
set { Contents = DefaultEncoding.GetBytes(value); }
}
/// <summary>
/// Gets or sets the date and time the <see cref="MockFileData"/> was created.
/// </summary>
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 { 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 { return lastWriteTime; }
set { lastWriteTime = value.ToUniversalTime(); }
}
private DateTimeOffset lastWriteTime;
#if FEATURE_FILE_SYSTEM_INFO_LINK_TARGET
/// <summary>
/// Gets or sets the link target of the <see cref="MockFileData"/>.
/// </summary>
public string LinkTarget { get; set; }
#endif
/// <summary>
/// Casts a string into <see cref="MockFileData"/>.
/// </summary>
/// <param name="s">The path of the <see cref="MockFileData"/> to be created.</param>
public static implicit operator MockFileData(string s)
{
return new MockFileData(s);
}
/// <summary>
/// Gets or sets the specified <see cref="FileAttributes"/> of the <see cref="MockFileData"/>.
/// </summary>
public FileAttributes Attributes { get; set; } = FileAttributes.Normal;
/// <summary>
/// Gets or sets <see cref="FileSecurity"/> of the <see cref="MockFileData"/>.
/// </summary>
[SupportedOSPlatform("windows")]
public FileSecurity AccessControl
{
get
{
// FileSecurity's constructor will throw PlatformNotSupportedException on non-Windows platform, so we initialize it in lazy way.
// This let's us use this class as long as we don't use AccessControl property.
return accessControl ?? (accessControl = new FileSecurity());
}
set { accessControl = value; }
}
/// <summary>
/// Gets or sets the File sharing mode for this file, this allows you to lock a file for reading or writing.
/// </summary>
public FileShare AllowedFileShare { get; set; } = FileShare.ReadWrite | FileShare.Delete;
#if FEATURE_UNIX_FILE_MODE
/// <summary>
/// Gets or sets the Unix file mode (permissions) for this file.
/// This allows you to configure the read, write and execute access for user, group and other.
/// </summary>
public UnixFileMode UnixMode { get; set; } = UnixFileMode.UserRead | UnixFileMode.GroupRead |
UnixFileMode.OtherRead | UnixFileMode.UserWrite;
#endif
/// <summary>
/// Checks whether the file is accessible for this type of FileAccess.
/// MockFileData can be configured to have FileShare.None, which indicates it is locked by a 'different process'.
///
/// If the file is 'locked by a different process', an IOException will be thrown.
/// If the file is read-only and is accessed for writing, an UnauthorizedAccessException will be thrown.
/// </summary>
/// <param name="path">The path is used in the exception message to match the message in real life situations</param>
/// <param name="access">The access type to check</param>
internal void CheckFileAccess(string path, FileAccess access)
{
if (!AllowedFileShare.HasFlag((FileShare)access))
{
throw CommonExceptions.ProcessCannotAccessFileInUse(path);
}
if (Attributes.HasFlag(FileAttributes.ReadOnly) && access.HasFlag(FileAccess.Write))
{
throw CommonExceptions.AccessDenied(path);
}
}
internal virtual MockFileData Clone()
{
return new MockFileData(this);
}
}