File: TestableFileSystem.cs
Web Access
Project: src\src\Compilers\Test\Core\Microsoft.CodeAnalysis.Test.Utilities.csproj (Microsoft.CodeAnalysis.Test.Utilities)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Roslyn.Utilities;
 
namespace Roslyn.Test.Utilities
{
    public delegate Stream OpenFileExFunc(string filePath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, out string normalizedFilePath);
    public delegate Stream OpenFileFunc(string filePath, FileMode mode, FileAccess access, FileShare share);
 
    public sealed class TestableFileSystem : ICommonCompilerFileSystem
    {
        private readonly Dictionary<string, TestableFile>? _map;
 
        public OpenFileFunc OpenFileFunc { get; private set; } = delegate { throw new InvalidOperationException(); };
        public OpenFileExFunc OpenFileExFunc { get; private set; } = (string _, FileMode _, FileAccess _, FileShare _, int _, FileOptions _, out string _) => throw new InvalidOperationException();
        public Func<string, bool> FileExistsFunc { get; private set; } = delegate { throw new InvalidOperationException(); };
 
        public Dictionary<string, TestableFile> Map => _map ?? throw new InvalidOperationException();
        public bool UsingMap => _map is not null;
 
        private TestableFileSystem(Dictionary<string, TestableFile>? map = null)
        {
            _map = map;
        }
 
        public Stream OpenFile(string filePath, FileMode mode, FileAccess access, FileShare share)
            => OpenFileFunc(filePath, mode, access, share);
 
        public Stream OpenFileEx(string filePath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, out string normalizedFilePath)
            => OpenFileExFunc(filePath, mode, access, share, bufferSize, options, out normalizedFilePath);
 
        public bool FileExists(string filePath) => FileExistsFunc(filePath);
 
        public static TestableFileSystem CreateForStandard(
            OpenFileFunc? openFileFunc = null,
            OpenFileExFunc? openFileExFunc = null,
            Func<string, bool>? fileExistsFunc = null)
            => new TestableFileSystem()
            {
                OpenFileFunc = openFileFunc ?? StandardFileSystem.Instance.OpenFile,
                OpenFileExFunc = openFileExFunc ?? StandardFileSystem.Instance.OpenFileEx,
                FileExistsFunc = fileExistsFunc ?? StandardFileSystem.Instance.FileExists,
            };
 
        public static TestableFileSystem CreateForOpenFile(OpenFileFunc openFileFunc)
            => new TestableFileSystem() { OpenFileFunc = openFileFunc };
 
        public static TestableFileSystem CreateForExistingPaths(IEnumerable<string> existingPaths, StringComparer? comparer = null)
        {
            comparer ??= StringComparer.OrdinalIgnoreCase;
            var set = new HashSet<string>(existingPaths, comparer);
            return new TestableFileSystem()
            {
                FileExistsFunc = filePath => set.Contains(filePath)
            };
        }
 
        public static TestableFileSystem CreateForFiles(params (string FilePath, TestableFile TestableFile)[] files)
        {
            var map = files.ToDictionary(
                x => x.FilePath,
                x => x.TestableFile);
            return CreateForMap(map);
        }
 
        public static TestableFileSystem CreateForMap() => CreateForMap(new());
 
        public static TestableFileSystem CreateForMap(Dictionary<string, TestableFile> map)
            => new TestableFileSystem(map)
            {
                OpenFileExFunc = (string filePath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, out string normalizedFilePath) =>
                {
                    normalizedFilePath = filePath;
                    return map[filePath].GetStream(access);
                },
 
                OpenFileFunc = (string filePath, FileMode mode, FileAccess access, FileShare share) => map[filePath].GetStream(access),
                FileExistsFunc = filePath => map.ContainsKey(filePath),
            };
    }
}