• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MeltyPlayer / MeltyTool / 21327634179

25 Jan 2026 05:35AM UTC coverage: 42.23% (-0.02%) from 42.249%
21327634179

push

github

MeltyPlayer
Okay, I think we're back to baseline now?

6863 of 18402 branches covered (37.29%)

Branch coverage included in aggregate %.

29404 of 67477 relevant lines covered (43.58%)

64428.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

24.15
/FinModelUtility/ImaginaryFileSystem/ImaginaryDirectory.cs
1
using System.Globalization;
2
using System.Text.RegularExpressions;
3

4
namespace System.IO.Abstractions.TestingHelpers;
5

6
using XFS = MockUnixSupport;
7

8
/// <inheritdoc />
9
#if FEATURE_SERIALIZABLE
10
[Serializable]
11
#endif
12
public class ImaginaryDirectory : DirectoryBase {
13
  private readonly IImaginaryFileDataAccessor imaginaryFileDataAccessor_;
14
  private string currentDirectory;
15

16
  /// <inheritdoc />
17
  public ImaginaryDirectory(IImaginaryFileDataAccessor imaginaryFileDataAccessor,
18
                       FileBase fileBase,
19
                       string currentDirectory) :
20
      this(imaginaryFileDataAccessor, currentDirectory) { }
×
21

22
  /// <inheritdoc />
23
  public ImaginaryDirectory(IImaginaryFileDataAccessor imaginaryFileDataAccessor,
24
                       string currentDirectory) : base(
22!
25
      imaginaryFileDataAccessor?.FileSystem) {
44✔
26
    this.currentDirectory = currentDirectory;
22✔
27
    this.imaginaryFileDataAccessor_ =
22!
28
        imaginaryFileDataAccessor ??
22✔
29
        throw new ArgumentNullException(nameof(imaginaryFileDataAccessor));
22✔
30
  }
22✔
31

32

33
  /// <inheritdoc />
34
  public override IDirectoryInfo CreateDirectory(string path) {
88✔
35
    return this.CreateDirectoryInternal(path);
88✔
36
  }
88✔
37

38
#if FEATURE_UNIX_FILE_MODE
39
        /// <inheritdoc />
40
        public override IDirectoryInfo CreateDirectory(string path, UnixFileMode unixCreateMode)
41
        {
×
42
            throw CommonExceptions.NotImplemented();
×
43
        }
44
#endif
45

46
  private IDirectoryInfo CreateDirectoryInternal(string path) {
88✔
47
    if (path == null) {
88!
48
      throw new ArgumentNullException(nameof(path));
×
49
    }
50

51
    if (path.Length == 0) {
88!
52
      throw new ArgumentException(
×
53
          StringResources.Manager.GetString(
×
54
              "PATH_CANNOT_BE_THE_EMPTY_STRING_OR_ALL_WHITESPACE"),
×
55
          "path");
×
56
    }
57

58
    if (this.imaginaryFileDataAccessor_.ImaginaryPathVerifier.HasIllegalCharacters(
88!
59
            path,
88✔
60
            true)) {
88✔
61
      throw CommonExceptions.IllegalCharactersInPath(nameof(path));
×
62
    }
63

64
    path = this.imaginaryFileDataAccessor_.Path.GetFullPath(path).TrimSlashes();
88✔
65
    if (ImaginaryUnixSupport.IsWindowsPlatform()) {
176✔
66
      path = path.TrimEnd(' ');
88✔
67
    }
88✔
68

69
    var existingFile = this.imaginaryFileDataAccessor_.GetFile(path);
88✔
70
    if (existingFile == null) {
176!
71
      this.imaginaryFileDataAccessor_.AddDirectory(path);
88✔
72
    } else if (!existingFile.IsDirectory) {
88!
73
      throw CommonExceptions.FileAlreadyExists("path");
×
74
    }
75

76
    var created = new ImaginaryDirectoryInfo(this.imaginaryFileDataAccessor_, path);
88✔
77

78
    return created;
88✔
79
  }
88✔
80

81
#if FEATURE_CREATE_SYMBOLIC_LINK
82
        /// <inheritdoc />
83
        public override IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget)
84
        {
×
85
          this.imaginaryFileDataAccessor_.ImaginaryPathVerifier.IsLegalAbsoluteOrRelative(path, nameof(path));
×
86
          this.imaginaryFileDataAccessor_.ImaginaryPathVerifier.IsLegalAbsoluteOrRelative(pathToTarget, nameof(pathToTarget));
×
87

88
            if (this.Exists(path))
×
89
            {
×
90
                throw CommonExceptions.FileAlreadyExists(nameof(path));
×
91
            }
92

93
            this.imaginaryFileDataAccessor_.AddDirectory(path);
×
94
            this.imaginaryFileDataAccessor_.GetFile(path).LinkTarget = pathToTarget;
×
95

96
            var directoryInfo =
×
97
 new ImaginaryDirectoryInfo(this.imaginaryFileDataAccessor_, path);
×
98
            directoryInfo.Attributes |= FileAttributes.ReparsePoint;
×
99
            return directoryInfo;
×
100
        }
×
101
#endif
102

103
#if FEATURE_CREATE_TEMP_SUBDIRECTORY
104
        /// <inheritdoc />
105
        public override IDirectoryInfo CreateTempSubdirectory(string prefix =
106
 null)
107
        {
×
108
            prefix ??= "";
×
109
            string potentialTempDirectory;
110

111
            // Perform directory name generation in a loop, just in case the randomly generated name already exists.
112
            do
113
            {
×
114
                var randomDir =
×
115
 $"{prefix}{this.FileSystem.Path.GetRandomFileName()}";
×
116
                potentialTempDirectory =
×
117
 Path.Combine(this.FileSystem.Path.GetTempPath(), randomDir);
×
118
            } while (this.Exists(potentialTempDirectory));
×
119

120
            return this.CreateDirectoryInternal(potentialTempDirectory);
×
121
        }
×
122
#endif
123

124
  /// <inheritdoc />
125
  public override void Delete(string path) {
×
126
    this.Delete(path, false);
×
127
  }
×
128

129

130
  /// <inheritdoc />
131
  public override void Delete(string path, bool recursive) {
88✔
132
    path = this.imaginaryFileDataAccessor_.Path.GetFullPath(path).TrimSlashes();
88✔
133

134
    var stringOps = this.imaginaryFileDataAccessor_.StringOperations;
88✔
135
    var pathWithDirectorySeparatorChar = $"{path}{Path.DirectorySeparatorChar}";
88✔
136

137
    var affectedPaths = this.imaginaryFileDataAccessor_
88✔
138
                            .AllPaths
88✔
139
                            .Where(p => stringOps.Equals(p, path) ||
6,005✔
140
                                        stringOps.StartsWith(
6,005✔
141
                                            p,
6,005✔
142
                                            pathWithDirectorySeparatorChar))
6,005✔
143
                            .ToList();
88✔
144

145
    if (!affectedPaths.Any()) {
88!
146
      throw CommonExceptions.PathDoesNotExistOrCouldNotBeFound(path);
×
147
    }
148

149
    if (!recursive && affectedPaths.Count > 1) {
88!
150
      throw new IOException("The directory specified by " +
×
151
                            path +
×
152
                            " is read-only, or recursive is false and " +
×
153
                            path +
×
154
                            " is not an empty directory.");
×
155
    }
156

157
    bool isFile = !this.imaginaryFileDataAccessor_.GetFile(path).IsDirectory;
88✔
158
    if (isFile) {
88!
159
      throw new IOException("The directory name is invalid.");
×
160
    }
161

162
    foreach (var affectedPath in affectedPaths) {
17,745✔
163
      this.imaginaryFileDataAccessor_.RemoveFile(affectedPath);
5,827✔
164
    }
5,827✔
165
  }
88✔
166

167

168
  /// <inheritdoc />
169
  public override bool Exists(string path) {
11,831✔
170
    if (path == "/") {
11,831!
171
      return true;
×
172
    }
173

174
    try {
11,831✔
175
      path = path.TrimSlashes();
11,831✔
176
      path = this.imaginaryFileDataAccessor_.Path.GetFullPath(path);
11,831✔
177
      return this.imaginaryFileDataAccessor_.GetFile(path)?.IsDirectory ??
11,831!
178
             false;
11,831✔
179
    } catch (Exception) {
×
180
      return false;
×
181
    }
182
  }
11,831✔
183

184

185
  /// <inheritdoc />
186
  public override DateTime GetCreationTime(string path) {
×
187
    return this.imaginaryFileDataAccessor_.File.GetCreationTime(path);
×
188
  }
×
189

190

191
  /// <inheritdoc />
192
  public override DateTime GetCreationTimeUtc(string path) {
×
193
    return this.imaginaryFileDataAccessor_.File.GetCreationTimeUtc(path);
×
194
  }
×
195

196
  /// <inheritdoc />
197
  public override string GetCurrentDirectory() {
145,819✔
198
    return this.currentDirectory;
145,819✔
199
  }
145,819✔
200

201
  /// <inheritdoc />
202
  public override string[] GetDirectories(string path) {
×
203
    return this.GetDirectories(path, "*");
×
204
  }
×
205

206
  /// <inheritdoc />
207
  public override string[] GetDirectories(string path, string searchPattern) {
×
208
    return this.GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
×
209
  }
×
210

211
  /// <inheritdoc />
212
  public override string[] GetDirectories(string path,
213
                                          string searchPattern,
214
                                          SearchOption searchOption) {
×
215
    return this.EnumerateDirectories(path, searchPattern, searchOption).ToArray();
×
216
  }
×
217

218
#if FEATURE_ENUMERATION_OPTIONS
219
        /// <inheritdoc />
220
        public override string[] GetDirectories(string path, string searchPattern,
221
            EnumerationOptions enumerationOptions)
222
        {
×
223
            return this.GetDirectories(path, "*", EnumerationOptionsToSearchOption_(enumerationOptions));
×
224
        }
×
225
#endif
226

227
  /// <inheritdoc />
228
  public override string GetDirectoryRoot(string path) {
×
229
    return Path.GetPathRoot(path);
×
230
  }
×
231

232
  /// <inheritdoc />
233
  public override string[] GetFiles(string path) {
176✔
234
    // Same as what the real framework does
235
    return this.GetFiles(path, "*");
176✔
236
  }
176✔
237

238
  /// <inheritdoc />
239
  public override string[] GetFiles(string path, string searchPattern) {
176✔
240
    // Same as what the real framework does
241
    return this.GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
176✔
242
  }
176✔
243

244
  /// <inheritdoc />
245
  public override string[] GetFiles(string path,
246
                                    string searchPattern,
247
                                    SearchOption searchOption) {
176✔
248
    return this.GetFilesInternal_(this.imaginaryFileDataAccessor_.AllFiles,
176✔
249
                                 path,
176✔
250
                                 searchPattern,
176✔
251
                                 searchOption);
176✔
252
  }
176✔
253

254
#if FEATURE_ENUMERATION_OPTIONS
255
        /// <inheritdoc />
256
        public override string[] GetFiles(string path, string searchPattern, EnumerationOptions enumerationOptions)
257
        {
×
258
            return this.GetFiles(path, searchPattern, EnumerationOptionsToSearchOption_(enumerationOptions));
×
259
        }
×
260
#endif
261

262
  private string[] GetFilesInternal_(
263
      IEnumerable<string> files,
264
      string path,
265
      string searchPattern,
266
      SearchOption searchOption) {
176✔
267
    if (path == null) {
176!
268
      throw new ArgumentNullException(nameof(path));
×
269
    }
270

271
    if (path.Any(c => Path.GetInvalidPathChars().Contains(c))) {
7,920!
272
      throw new ArgumentException("Invalid character(s) in path", nameof(path));
×
273
    }
274

275
    this.CheckSearchPattern(searchPattern);
176✔
276
    if (searchPattern.Equals(string.Empty,
176!
277
                             StringComparison.OrdinalIgnoreCase)) {
176✔
278
      searchPattern = "*";
×
279
    }
×
280

281
    path = path.TrimSlashes();
176✔
282
    path = path.NormalizeSlashes();
176✔
283
    path = this.imaginaryFileDataAccessor_.Path.GetFullPath(path);
176✔
284

285
    if (!this.Exists(path)) {
176!
286
      throw CommonExceptions.CouldNotFindPartOfPath(path);
×
287
    }
288

289
    if (!path.EndsWith(Path.DirectorySeparatorChar.ToString())) {
352✔
290
      path += Path.DirectorySeparatorChar;
176✔
291
    }
176✔
292

293
    var isUnix = ImaginaryUnixSupport.IsUnixPlatform();
176✔
294

295
    var allDirectoriesPattern = isUnix
176!
296
        ? @"([^<>:""/|?*]*/)*"
176✔
297
        : @"([^<>:""/\\|?*]*\\)*";
176✔
298

299
    var searchEndInStarDot = searchPattern.EndsWith(@"*.");
176✔
300

301
    string fileNamePattern;
302
    string pathPatternNoExtension = string.Empty;
176✔
303
    string pathPatternEndsInDot = string.Empty;
176✔
304
    string pathPatternSpecial = null;
176✔
305

306
    if (searchPattern == "*") {
352!
307
      fileNamePattern = isUnix ? @"[^/]*?/?" : @"[^\\]*?\\?";
176!
308
    } else {
176✔
309
      fileNamePattern = Regex.Escape(searchPattern)
×
310
                             .Replace(@"\*",
×
311
                                      isUnix
×
312
                                          ? @"[^<>:""/|?*]*?"
×
313
                                          : @"[^<>:""/\\|?*]*?")
×
314
                             .Replace(@"\?",
×
315
                                      isUnix
×
316
                                          ? @"[^<>:""/|?*]?"
×
317
                                          : @"[^<>:""/\\|?*]?");
×
318

319
      var extension = Path.GetExtension(searchPattern);
×
320
      bool hasExtensionLengthOfThree = extension != null &&
×
321
                                       extension.Length == 4 &&
×
322
                                       !extension.Contains("*") &&
×
323
                                       !extension.Contains("?");
×
324
      if (hasExtensionLengthOfThree) {
×
325
        var fileNamePatternSpecial =
×
326
            string.Format(CultureInfo.InvariantCulture,
×
327
                          "{0}[^.]",
×
328
                          fileNamePattern);
×
329
        pathPatternSpecial = string.Format(
×
330
            CultureInfo.InvariantCulture,
×
331
            isUnix ? @"(?i:^{0}{1}{2}(?:/?)$)" : @"(?i:^{0}{1}{2}(?:\\?)$)",
×
332
            Regex.Escape(path),
×
333
            searchOption == SearchOption.AllDirectories
×
334
                ? allDirectoriesPattern
×
335
                : string.Empty,
×
336
            fileNamePatternSpecial);
×
337
      }
×
338
    }
×
339

340
    var pathPattern = string.Format(
176!
341
        CultureInfo.InvariantCulture,
176✔
342
        isUnix ? @"(?i:^{0}{1}{2}(?:/?)$)" : @"(?i:^{0}{1}{2}(?:\\?)$)",
176✔
343
        Regex.Escape(path),
176✔
344
        searchOption == SearchOption.AllDirectories
176✔
345
            ? allDirectoriesPattern
176✔
346
            : string.Empty,
176✔
347
        fileNamePattern);
176✔
348

349
    if (searchEndInStarDot) {
176!
350
      pathPatternNoExtension
×
351
          = ReplaceLastOccurrence_(pathPattern, @"]*?\.", @"\.]*?[.]*");
×
352
      pathPatternEndsInDot
×
353
          = ReplaceLastOccurrence_(pathPattern, @"]*?\.", @"]*?[.]{1,}");
×
354
    }
×
355

356
    return files.Where(p =>
176✔
357
                           !searchEndInStarDot
7,713!
358
                               ? (Regex.IsMatch(p, pathPattern) ||
7,713✔
359
                                  (pathPatternSpecial != null &&
7,713✔
360
                                   Regex.IsMatch(p, pathPatternSpecial)))
7,713✔
361
                               : (Regex.IsMatch(p, pathPatternNoExtension) ||
7,713✔
362
                                  Regex.IsMatch(p, pathPatternEndsInDot))
7,713✔
363
                )
176✔
364
                .ToArray();
176✔
365
  }
176✔
366

367
  /// <inheritdoc />
368
  public override string[] GetFileSystemEntries(string path) {
×
369
    return this.GetFileSystemEntries(path, "*");
×
370
  }
×
371

372
  /// <inheritdoc />
373
  public override string[] GetFileSystemEntries(
374
      string path,
375
      string searchPattern) {
×
376
    var dirs = this.GetDirectories(path, searchPattern);
×
377
    var files = this.GetFiles(path, searchPattern);
×
378

379
    return dirs.Union(files).ToArray();
×
380
  }
×
381

382
  /// <inheritdoc />
383
  public override string[] GetFileSystemEntries(
384
      string path,
385
      string searchPattern,
386
      SearchOption searchOption) {
×
387
    var dirs = this.GetDirectories(path, searchPattern, searchOption);
×
388
    var files = this.GetFiles(path, searchPattern, searchOption);
×
389

390
    return dirs.Union(files).ToArray();
×
391
  }
×
392

393
#if FEATURE_ENUMERATION_OPTIONS
394
        /// <inheritdoc />
395
        public override string[] GetFileSystemEntries(string path, string searchPattern,
396
            EnumerationOptions enumerationOptions)
397
        {
×
398
            return this.GetFileSystemEntries(path, "*", EnumerationOptionsToSearchOption_(enumerationOptions));
×
399
        }
×
400
#endif
401

402
  /// <inheritdoc />
403
  public override DateTime GetLastAccessTime(string path) {
×
404
    return this.imaginaryFileDataAccessor_.File.GetLastAccessTime(path);
×
405
  }
×
406

407
  /// <inheritdoc />
408
  public override DateTime GetLastAccessTimeUtc(string path) {
×
409
    return this.imaginaryFileDataAccessor_.File.GetLastAccessTimeUtc(path);
×
410
  }
×
411

412
  /// <inheritdoc />
413
  public override DateTime GetLastWriteTime(string path) {
×
414
    return this.imaginaryFileDataAccessor_.File.GetLastWriteTime(path);
×
415
  }
×
416

417
  /// <inheritdoc />
418
  public override DateTime GetLastWriteTimeUtc(string path) {
×
419
    return this.imaginaryFileDataAccessor_.File.GetLastWriteTimeUtc(path);
×
420
  }
×
421

422
  /// <inheritdoc />
423
  public override string[] GetLogicalDrives() {
×
424
    return this.imaginaryFileDataAccessor_
×
425
               .AllDirectories
×
426
               .Select(d => new ImaginaryDirectoryInfo(
×
427
                           this.imaginaryFileDataAccessor_,
×
428
                           d).Root.FullName)
×
429
               .Select(r => this.imaginaryFileDataAccessor_.StringOperations
×
430
                                .ToUpper(r))
×
431
               .Distinct()
×
432
               .ToArray();
×
433
  }
×
434

435
  /// <inheritdoc />
436
  public override IDirectoryInfo GetParent(string path) {
×
437
    if (path == null) {
×
438
      throw new ArgumentNullException(nameof(path));
×
439
    }
440

441
    if (path.Length == 0) {
×
442
      throw new ArgumentException(
×
443
          StringResources.Manager.GetString(
×
444
              "PATH_CANNOT_BE_THE_EMPTY_STRING_OR_ALL_WHITESPACE"),
×
445
          "path");
×
446
    }
447

448
    if (this.imaginaryFileDataAccessor_.ImaginaryPathVerifier.HasIllegalCharacters(
×
449
            path,
×
450
            false)) {
×
451
      throw new ArgumentException("Path contains invalid path characters.",
×
452
                                  "path");
×
453
    }
454

455
    var absolutePath = this.imaginaryFileDataAccessor_.Path.GetFullPath(path);
×
456
    var sepAsString = this.imaginaryFileDataAccessor_.Path
×
457
                          .DirectorySeparatorChar.ToString();
×
458
    var lastIndex = 0;
×
459

460
    if (absolutePath != sepAsString) {
×
461
      var startIndex
×
462
          = this.imaginaryFileDataAccessor_.StringOperations.EndsWith(
×
463
              absolutePath,
×
464
              sepAsString)
×
465
              ? absolutePath.Length - 1
×
466
              : absolutePath.Length;
×
467
      lastIndex = absolutePath.LastIndexOf(
×
468
          this.imaginaryFileDataAccessor_.Path.DirectorySeparatorChar,
×
469
          startIndex - 1);
×
470

471
      if (lastIndex < 0) {
×
472
        return null;
×
473
      }
474
    }
×
475

476
    var parentPath = absolutePath.Substring(0, lastIndex);
×
477

478
    if (string.IsNullOrEmpty(parentPath)) {
×
479
      // On the Unix platform, the parent of a path consisting of a slash followed by
480
      // non-slashes is the root, '/'.
481
      if (ImaginaryUnixSupport.IsUnixPlatform()) {
×
482
        absolutePath = absolutePath.TrimSlashes();
×
483

484
        if (absolutePath.Length > 1 &&
×
485
            absolutePath.LastIndexOf(this.imaginaryFileDataAccessor_.Path
×
486
                                         .DirectorySeparatorChar) ==
×
487
            0) {
×
488
          return new ImaginaryDirectoryInfo(this.imaginaryFileDataAccessor_,
×
489
                                       this.imaginaryFileDataAccessor_.Path
×
490
                                           .DirectorySeparatorChar.ToString());
×
491
        }
492
      }
×
493

494
      return null;
×
495
    }
496

497
    return new ImaginaryDirectoryInfo(this.imaginaryFileDataAccessor_, parentPath);
×
498
  }
×
499

500
  /// <inheritdoc />
501
  public override void Move(string sourceDirName, string destDirName) {
×
502
    var fullSourcePath = this.imaginaryFileDataAccessor_.Path
×
503
                             .GetFullPath(sourceDirName)
×
504
                             .TrimSlashes();
×
505
    var fullDestPath = this.imaginaryFileDataAccessor_.Path
×
506
                           .GetFullPath(destDirName)
×
507
                           .TrimSlashes();
×
508

509
    if (string.Equals(fullSourcePath, fullDestPath, StringComparison.Ordinal)) {
×
510
      throw new IOException("Source and destination path must be different.");
×
511
    }
512

513
    //if we're moving a file, not a directory, call the appropriate file moving function.
514
    var fileData = this.imaginaryFileDataAccessor_.GetFile(fullSourcePath);
×
515
    if (fileData?.Attributes.HasFlag(FileAttributes.Directory) == false) {
×
516
      this.imaginaryFileDataAccessor_.File.Move(fullSourcePath, fullDestPath);
×
517
      return;
×
518
    }
519

520
    var sourceRoot
×
521
        = this.imaginaryFileDataAccessor_.Path.GetPathRoot(fullSourcePath);
×
522
    var destinationRoot
×
523
        = this.imaginaryFileDataAccessor_.Path.GetPathRoot(fullDestPath);
×
524

525
    if (!this.imaginaryFileDataAccessor_.StringOperations.Equals(
×
526
            sourceRoot,
×
527
            destinationRoot)) {
×
528
      throw new IOException(
×
529
          "Source and destination path must have identical roots. Move will not work across volumes.");
×
530
    }
531

532
    if (!this.imaginaryFileDataAccessor_.Directory.Exists(fullSourcePath)) {
×
533
      throw CommonExceptions.CouldNotFindPartOfPath(sourceDirName);
×
534
    }
535

536
    if (!this.imaginaryFileDataAccessor_.Directory.GetParent(fullDestPath)
×
537
             .Exists) {
×
538
      throw CommonExceptions.CouldNotFindPartOfPath(destDirName);
×
539
    }
540

541
    if (this.imaginaryFileDataAccessor_.Directory.Exists(fullDestPath) ||
×
542
        this.imaginaryFileDataAccessor_.File.Exists(fullDestPath)) {
×
543
      // In Windows, file/dir names are case sensetive, C:\\temp\\src and C:\\temp\\SRC and treated different
544
      if (ImaginaryUnixSupport.IsUnixPlatform() ||
×
545
          !string.Equals(fullSourcePath,
×
546
                         fullDestPath,
×
547
                         StringComparison.OrdinalIgnoreCase)) {
×
548
        throw CommonExceptions.CannotCreateBecauseSameNameAlreadyExists(
×
549
            fullDestPath);
×
550
      }
551
    }
×
552

553
    this.imaginaryFileDataAccessor_.MoveDirectory(fullSourcePath, fullDestPath);
×
554
  }
×
555

556
#if FEATURE_CREATE_SYMBOLIC_LINK
557
        /// <inheritdoc />
558
        public override IFileSystemInfo ResolveLinkTarget(string linkPath, bool returnFinalTarget)
559
        {
×
560
            var initialContainer = this.imaginaryFileDataAccessor_.GetFile(linkPath);
×
561
            if (initialContainer.LinkTarget != null)
×
562
            {
×
563
                var nextLocation = initialContainer.LinkTarget;
×
564
                var nextContainer = this.imaginaryFileDataAccessor_.GetFile(nextLocation);
×
565

566
                if (returnFinalTarget)
×
567
                {
×
568
                    // The maximum number of symbolic links that are followed:
569
                    // https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.resolvelinktarget?view=net-6.0#remarks
570
                    int maxResolveLinks = XFS.IsWindowsPlatform() ? 63 : 40;
×
571
                    for (int i = 1; i < maxResolveLinks; i++)
×
572
                    {
×
573
                        if (nextContainer.LinkTarget == null)
×
574
                        {
×
575
                            break;
×
576
                        }
577
                        nextLocation = nextContainer.LinkTarget;
×
578
                        nextContainer = this.imaginaryFileDataAccessor_.GetFile(nextLocation);
×
579
                    }
×
580

581
                    if (nextContainer.LinkTarget != null)
×
582
                    {
×
583
                        throw CommonExceptions.NameCannotBeResolvedByTheSystem(linkPath);
×
584
                    }
585
                }
×
586

587
                if (nextContainer.IsDirectory)
×
588
                {
×
589
                    return new ImaginaryDirectoryInfo(this.imaginaryFileDataAccessor_, nextLocation);
×
590
                }
591
                else
592
                {
×
593
                    return new ImaginaryFileInfo(this.imaginaryFileDataAccessor_, nextLocation);
×
594
                }
595
            }
596
            throw CommonExceptions.NameCannotBeResolvedByTheSystem(linkPath);
×
597
        }
×
598

599
#endif
600

601
  /// <inheritdoc />
602
  public override void SetCreationTime(string path, DateTime creationTime) {
×
603
    this.imaginaryFileDataAccessor_.File.SetCreationTime(path, creationTime);
×
604
  }
×
605

606
  /// <inheritdoc />
607
  public override void
608
      SetCreationTimeUtc(string path, DateTime creationTimeUtc) {
×
609
    this.imaginaryFileDataAccessor_.File.SetCreationTimeUtc(
×
610
        path,
×
611
        creationTimeUtc);
×
612
  }
×
613

614
  /// <inheritdoc />
615
  public override void SetCurrentDirectory(string path) {
×
616
    this.currentDirectory = this.imaginaryFileDataAccessor_.Path.GetFullPath(path);
×
617
  }
×
618

619
  /// <inheritdoc />
620
  public override void SetLastAccessTime(string path, DateTime lastAccessTime) {
×
621
    this.imaginaryFileDataAccessor_.File
×
622
        .SetLastAccessTime(path, lastAccessTime);
×
623
  }
×
624

625
  /// <inheritdoc />
626
  public override void SetLastAccessTimeUtc(string path,
627
                                            DateTime lastAccessTimeUtc) {
×
628
    this.imaginaryFileDataAccessor_.File.SetLastAccessTimeUtc(
×
629
        path,
×
630
        lastAccessTimeUtc);
×
631
  }
×
632

633
  /// <inheritdoc />
634
  public override void SetLastWriteTime(string path, DateTime lastWriteTime) {
×
635
    this.imaginaryFileDataAccessor_.File.SetLastWriteTime(path, lastWriteTime);
×
636
  }
×
637

638
  /// <inheritdoc />
639
  public override void SetLastWriteTimeUtc(string path,
640
                                           DateTime lastWriteTimeUtc) {
×
641
    this.imaginaryFileDataAccessor_.File.SetLastWriteTimeUtc(
×
642
        path,
×
643
        lastWriteTimeUtc);
×
644
  }
×
645

646
  /// <inheritdoc />
647
  public override IEnumerable<string> EnumerateDirectories(string path) {
×
648
    return this.EnumerateDirectories(path, "*");
×
649
  }
×
650

651
  /// <inheritdoc />
652
  public override IEnumerable<string> EnumerateDirectories(
653
      string path,
654
      string searchPattern) {
×
655
    return this.EnumerateDirectories(path,
×
656
                                     searchPattern,
×
657
                                     SearchOption.TopDirectoryOnly);
×
658
  }
×
659

660
  /// <inheritdoc />
661
  public override IEnumerable<string> EnumerateDirectories(
662
      string path,
663
      string searchPattern,
664
      SearchOption searchOption) {
×
665
    this.imaginaryFileDataAccessor_.ImaginaryPathVerifier.IsLegalAbsoluteOrRelative(
×
666
        path,
×
667
        "path");
×
668
    var originalPath = path;
×
669
    path = path.TrimSlashes();
×
670
    path = this.imaginaryFileDataAccessor_.Path.GetFullPath(path);
×
671
    return this.GetFilesInternal_(this.imaginaryFileDataAccessor_.AllDirectories,
×
672
                                 path,
×
673
                                 searchPattern,
×
674
                                 searchOption)
×
675
               .Where(p => !this.imaginaryFileDataAccessor_.StringOperations.Equals(
×
676
                          p,
×
677
                          path))
×
678
               .Select(p => this.FixPrefix(p, originalPath));
×
679
  }
×
680

681
  private string FixPrefix(string path, string originalPath) {
×
682
    var normalizedOriginalPath
×
683
        = this.imaginaryFileDataAccessor_.Path.GetFullPath(originalPath);
×
684
    var pathWithoutOriginalPath = path.Substring(normalizedOriginalPath.Length)
×
685
                                      .TrimStart(
×
686
                                          this.imaginaryFileDataAccessor_.Path
×
687
                                              .DirectorySeparatorChar);
×
688
    return this.imaginaryFileDataAccessor_.Path.Combine(
×
689
        originalPath,
×
690
        pathWithoutOriginalPath);
×
691
  }
×
692

693
#if FEATURE_ENUMERATION_OPTIONS
694
        /// <inheritdoc />
695
        public override IEnumerable<string> EnumerateDirectories(string path, string searchPattern, EnumerationOptions enumerationOptions)
696
        {
×
697
            var searchOption =
×
698
 enumerationOptions.RecurseSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
×
699
            return this.EnumerateDirectories(path, searchPattern, searchOption);
×
700
        }
×
701
#endif
702

703
  /// <inheritdoc />
704
  public override IEnumerable<string> EnumerateFiles(string path) {
88✔
705
    return this.GetFiles(path);
88✔
706
  }
88✔
707

708
  /// <inheritdoc />
709
  public override IEnumerable<string> EnumerateFiles(
710
      string path,
711
      string searchPattern) {
×
712
    return this.GetFiles(path, searchPattern);
×
713
  }
×
714

715
  /// <inheritdoc />
716
  public override IEnumerable<string> EnumerateFiles(
717
      string path,
718
      string searchPattern,
719
      SearchOption searchOption) {
×
720
    return this.GetFiles(path, searchPattern, searchOption);
×
721
  }
×
722

723
#if FEATURE_ENUMERATION_OPTIONS
724
        /// <inheritdoc />
725
        public override IEnumerable<string> EnumerateFiles(string path, string searchPattern, EnumerationOptions enumerationOptions)
726
        {
×
727
            var searchOption =
×
728
 enumerationOptions.RecurseSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
×
729
            return this.GetFiles(path, searchPattern, searchOption);
×
730
        }
×
731
#endif
732

733
  /// <inheritdoc />
734
  public override IEnumerable<string> EnumerateFileSystemEntries(string path) {
×
735
    return this.GetFileSystemEntries(path);
×
736
  }
×
737

738
  /// <inheritdoc />
739
  public override IEnumerable<string> EnumerateFileSystemEntries(
740
      string path,
741
      string searchPattern) {
×
742
    return this.GetFileSystemEntries(path, searchPattern);
×
743
  }
×
744

745
  /// <inheritdoc />
746
  public override IEnumerable<string> EnumerateFileSystemEntries(
747
      string path,
748
      string searchPattern,
749
      SearchOption searchOption) {
×
750
    return this.GetFileSystemEntries(path, searchPattern, searchOption);
×
751
  }
×
752

753
#if FEATURE_ENUMERATION_OPTIONS
754
        /// <inheritdoc />
755
        public override IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern, EnumerationOptions enumerationOptions)
756
        {
×
757
            var searchOption =
×
758
 enumerationOptions.RecurseSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
×
759
            var fileSystemEntries =
×
760
 new List<string>(this.GetFiles(path, searchPattern, searchOption));
×
761
            fileSystemEntries.AddRange(this.GetDirectories(path, searchPattern, searchOption));
×
762
            return fileSystemEntries;
×
763
        }
×
764
#endif
765

766
  private string EnsureAbsolutePath(string path) {
×
767
    return Path.IsPathRooted(path)
×
768
        ? path
×
769
        : Path.Combine(this.GetCurrentDirectory(), path);
×
770
  }
×
771

772
  private void CheckSearchPattern(string searchPattern) {
176✔
773
    if (searchPattern == null) {
176!
774
      throw new ArgumentNullException(nameof(searchPattern));
×
775
    }
776

777
    const string TWO_DOTS = "..";
778
    Func<ArgumentException> createException = ()
176✔
779
        => new ArgumentException(
176✔
780
            @"Search pattern cannot contain "".."" to move up directories and can be contained only internally in file/directory names, as in ""a..b"".",
176✔
781
            searchPattern);
176✔
782

783
    if (this.imaginaryFileDataAccessor_.StringOperations.EndsWith(
176!
784
            searchPattern,
176✔
785
            TWO_DOTS)) {
176✔
786
      throw createException();
×
787
    }
788

789
    var position
176✔
790
        = this.imaginaryFileDataAccessor_.StringOperations.IndexOf(
176✔
791
            searchPattern,
176✔
792
            TWO_DOTS);
176✔
793

794
    if (position >= 0) {
176!
795
      var characterAfterTwoDots = searchPattern[position + 2];
×
796

797
      if (characterAfterTwoDots == Path.DirectorySeparatorChar ||
×
798
          characterAfterTwoDots == Path.AltDirectorySeparatorChar) {
×
799
        throw createException();
×
800
      }
801
    }
×
802

803
    var invalidPathChars = Path.GetInvalidPathChars();
176✔
804
    if (searchPattern.IndexOfAny(invalidPathChars) > -1) {
176!
805
      throw CommonExceptions.IllegalCharactersInPath(nameof(searchPattern));
×
806
    }
807
  }
176✔
808

809
  private static string ReplaceLastOccurrence_(string source,
810
                                               string find,
811
                                               string replace) {
×
812
    if (source == null) {
×
813
      return source;
×
814
    }
815

816
    var place = source.LastIndexOf(find);
×
817

818
    if (place == -1) {
×
819
      return source;
×
820
    }
821

822
    var result = source.Remove(place, find.Length).Insert(place, replace);
×
823
    return result;
×
824
  }
×
825

826
#if FEATURE_ENUMERATION_OPTIONS
827
        private static SearchOption EnumerationOptionsToSearchOption_(EnumerationOptions enumerationOptions)
828
        {
×
829
            static Exception CreateExceptionForUnsupportedProperty(string propertyName)
830
            {
×
831
                return new NotSupportedException(
×
832
                    $"Changing EnumerationOptions.{propertyName} is not yet implemented for the mock file system."
×
833
                );
×
834
            }
×
835

836
            if (enumerationOptions.AttributesToSkip != (FileAttributes.System | FileAttributes.Hidden))
×
837
            {
×
838
                throw CreateExceptionForUnsupportedProperty("AttributesToSkip");
×
839
            }
840
            if (!enumerationOptions.IgnoreInaccessible)
×
841
            {
×
842
                throw CreateExceptionForUnsupportedProperty("IgnoreInaccessible");
×
843
            }
844
            if (enumerationOptions.MatchCasing != MatchCasing.PlatformDefault)
×
845
            {
×
846
                throw CreateExceptionForUnsupportedProperty("MatchCasing");
×
847
            }
848
            if (enumerationOptions.MatchType != MatchType.Simple)
×
849
            {
×
850
                throw CreateExceptionForUnsupportedProperty("MatchType");
×
851
            }
852
            if (enumerationOptions.ReturnSpecialDirectories)
×
853
            {
×
854
                throw CreateExceptionForUnsupportedProperty("ReturnSpecialDirectories");
×
855
            }
856

857
            return enumerationOptions.RecurseSubdirectories
×
858
                ? SearchOption.AllDirectories
×
859
                : SearchOption.TopDirectoryOnly;
×
860
        }
×
861
#endif
862
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc