Skip to content
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

Add TestableIO.System.IO.Abstractions.Analyzers #1915

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
6 changes: 3 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
<PackageVersion Include="RabbitMQ.Client" Version="6.8.1" />
<PackageVersion Include="Spectre.Console" Version="0.49.1" />
<PackageVersion Include="StackExchange.Redis" Version="2.8.0" />
<PackageVersion Include="System.IO.Abstractions" Version="21.0.29" />
<PackageVersion Include="System.IO.FileSystem" Version="4.3.0" />
<PackageVersion Include="TestableIO.System.IO.Abstractions.Wrappers" Version="21.0.29" />
<PackageVersion Include="TestableIO.System.IO.Abstractions.Analyzers" Version="2022.0.0" />
<PackageVersion Include="Terminal.Gui" Version="1.17.1" />
<PackageVersion Include="YamlDotNet" Version="16.0.0" />
<!-- Test Packages -->
Expand All @@ -38,6 +38,6 @@
<PackageVersion Include="NUnit.Analyzers" Version="4.3.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageVersion Include="NunitXml.TestLogger" Version="4.0.254" />
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="21.0.29" />
<PackageVersion Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="21.0.29" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using SmiServices.Common.Execution;
using SmiServices.Common.Options;
using System.Collections.Generic;
using System.IO.Abstractions;

namespace SmiServices.Applications.DicomDirectoryProcessor
{
Expand All @@ -18,20 +19,22 @@ public static class DicomDirectoryProcessor
/// Arguments. There should be exactly one argument that specified the
/// path to the top level directory that is be searched.
/// </param>
public static int Main(IEnumerable<string> args)
/// <param name="fileSystem"></param>
public static int Main(IEnumerable<string> args, IFileSystem? fileSystem = null)
{
int ret = SmiCliInit
.ParseAndRun<DicomDirectoryProcessorCliOptions>(
args,
typeof(DicomDirectoryProcessor),
OnParse
OnParse,
fileSystem ?? new FileSystem()
);
return ret;
}

private static int OnParse(GlobalOptions globals, DicomDirectoryProcessorCliOptions parsedOptions)
private static int OnParse(GlobalOptions globals, IFileSystem fileSystem, DicomDirectoryProcessorCliOptions parsedOptions)
{
var bootstrapper = new MicroserviceHostBootstrapper(() => new DicomDirectoryProcessorHost(globals, parsedOptions));
var bootstrapper = new MicroserviceHostBootstrapper(() => new DicomDirectoryProcessorHost(globals, parsedOptions, fileSystem));
int ret = bootstrapper.Main();
return ret;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,6 @@ public class DicomDirectoryProcessorCliOptions : CliOptions
public string? DirectoryFormat { get; set; }


public DirectoryInfo? ToProcessDir
{
get
{
return ToProcess == null
? null
: new DirectoryInfo(ToProcess);
}
set => ToProcess = value?.FullName ?? throw new ArgumentNullException(nameof(value));
}

[Usage]
public static IEnumerable<Example> Examples
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;

namespace SmiServices.Applications.DicomDirectoryProcessor
{
Expand All @@ -19,32 +20,35 @@ public class DicomDirectoryProcessorHost : MicroserviceHost
/// Constructor
/// </summary>
/// <param name="cliOptions">Common microservices options. Must contain details for an message exchange labelled as "accessionDirectories"</param>
/// <param name="fileSystem"></param>
/// <param name="globals">Configuration settings for the program</param>
public DicomDirectoryProcessorHost(GlobalOptions globals, DicomDirectoryProcessorCliOptions cliOptions)
: base(globals)
public DicomDirectoryProcessorHost(GlobalOptions globals, DicomDirectoryProcessorCliOptions cliOptions, IFileSystem? fileSystem = null)
: base(globals, fileSystem ?? new FileSystem())
{
_cliOptions = cliOptions;

IDirectoryInfo toProcessDir = FileSystem.DirectoryInfo.New(cliOptions.ToProcess);

if (!cliOptions.DirectoryFormat!.ToLower().Equals("list"))
{
// TODO(rkm 2020-02-12) I think we want to check this regardless of the mode
// (bp 2020-02-13) By not doing this check on list means that the list of paths is not required to be in PACS and can be imported from anywhere
if (!Directory.Exists(globals.FileSystemOptions!.FileSystemRoot))
throw new ArgumentException("Cannot find the FileSystemRoot specified in the given MicroservicesOptions (" + globals.FileSystemOptions.FileSystemRoot + ")");
if (!FileSystem.Directory.Exists(globals.FileSystemOptions!.FileSystemRoot))
throw new ArgumentException($"Cannot find the FileSystemRoot specified in the given MicroservicesOptions ({globals.FileSystemOptions.FileSystemRoot})");

if (!cliOptions.ToProcessDir!.Exists)
throw new ArgumentException("Could not find directory " + cliOptions.ToProcessDir.FullName);
if (!toProcessDir.Exists)
throw new ArgumentException($"Could not find directory {toProcessDir.FullName}");

if (!cliOptions.ToProcessDir.FullName.StartsWith(globals.FileSystemOptions.FileSystemRoot, true, CultureInfo.CurrentCulture))
throw new ArgumentException("Directory parameter (" + cliOptions.ToProcessDir.FullName + ") must be below the FileSystemRoot (" + globals.FileSystemOptions.FileSystemRoot + ")");
if (!toProcessDir.FullName.StartsWith(globals.FileSystemOptions.FileSystemRoot, true, CultureInfo.CurrentCulture))
throw new ArgumentException($"Directory parameter ({toProcessDir.FullName}) must be below the FileSystemRoot ({globals.FileSystemOptions.FileSystemRoot})");
}
else
{
if (!File.Exists(cliOptions.ToProcessDir!.FullName))
throw new ArgumentException("Could not find accession directory list file (" + cliOptions.ToProcessDir.FullName + ")");
if (!FileSystem.File.Exists(toProcessDir.FullName))
throw new ArgumentException($"Could not find accession directory list file ({toProcessDir.FullName})");

if (!Path.GetExtension(cliOptions.ToProcessDir.FullName).Equals(".csv"))
throw new ArgumentException("When in 'list' mode, path to accession directory file of format .csv expected (" + cliOptions.ToProcessDir.FullName + ")");
if (!FileSystem.Path.GetExtension(toProcessDir.FullName).Equals(".csv"))
throw new ArgumentException($"When in 'list' mode, path to accession directory file of format .csv expected ({toProcessDir.FullName})");
}

switch (cliOptions.DirectoryFormat.ToLower())
Expand Down Expand Up @@ -84,9 +88,11 @@ public DicomDirectoryProcessorHost(GlobalOptions globals, DicomDirectoryProcesso
/// </summary>
public override void Start()
{
IDirectoryInfo toProcessDir = FileSystem.DirectoryInfo.New(_cliOptions.ToProcess);

try
{
_ddf.SearchForDicomDirectories(_cliOptions.ToProcessDir!.FullName);
_ddf.SearchForDicomDirectories(toProcessDir.FullName);
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ protected void FoundNewDicomDirectory(string dir)
{
Logger.Debug("DicomDirectoryFinder: Found " + dir);

string dirPath = Path.GetFullPath(dir).TrimEnd(Path.DirectorySeparatorChar);
string dirPath = FileSystem.Path.GetFullPath(dir).TrimEnd(FileSystem.Path.DirectorySeparatorChar);

if (dirPath.StartsWith(FileSystemRoot))
dirPath = dirPath.Remove(0, FileSystemRoot.Length);
Expand Down
11 changes: 6 additions & 5 deletions src/SmiServices/Applications/DicomLoader/DicomLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -26,14 +27,14 @@ namespace SmiServices.Applications.DicomLoader;
public static class DicomLoader
{
private static CancellationTokenSource? _cts;
public static int Main(IEnumerable<string> args)
public static int Main(IEnumerable<string> args, IFileSystem? fileSystem = null)
{
return SmiCliInit.ParseAndRun<DicomLoaderOptions>(args, typeof(DicomLoader), OnParse);
return SmiCliInit.ParseAndRun<DicomLoaderOptions>(args, typeof(DicomLoader), OnParse, fileSystem ?? new FileSystem());
}

private static int OnParse(GlobalOptions g, DicomLoaderOptions cliOptions)
private static int OnParse(GlobalOptions g, IFileSystem fileSystem, DicomLoaderOptions cliOptions)
{
return OnParse(g, cliOptions, null);
return OnParse(g, fileSystem, cliOptions, null);
}

private static void CancelHandler(object? _, ConsoleCancelEventArgs a)
Expand All @@ -42,7 +43,7 @@ private static void CancelHandler(object? _, ConsoleCancelEventArgs a)
a.Cancel = true;
}

private static int OnParse(GlobalOptions go, DicomLoaderOptions dicomLoaderOptions, Stream? fileList)
private static int OnParse(GlobalOptions go, IFileSystem fileSystem, DicomLoaderOptions dicomLoaderOptions, Stream? fileList)
{
if (go.MongoDatabases?.DicomStoreOptions is null)
throw new InvalidOperationException("MongoDatabases or DICOM store options not set");
Expand Down
13 changes: 8 additions & 5 deletions src/SmiServices/Applications/DicomLoader/Loader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -257,9 +258,10 @@ public void Report(CancellationToken? cancellationToken = null)
private readonly DicomLoaderOptions _loadOptions;
private readonly ParallelDLEHost? _parallelDleHost;
private readonly LoadMetadata? _lmd;
private readonly IFileSystem _fileSystem;

public Loader(IMongoDatabase database, string imageCollection, string seriesCollection,
DicomLoaderOptions loadOptions, ParallelDLEHost? parallelDleHost, LoadMetadata? lmd)
DicomLoaderOptions loadOptions, ParallelDLEHost? parallelDleHost, LoadMetadata? lmd, IFileSystem? fileSystem = null)
{
_imageQueueLock = new object();
_seriesListLock = new ReaderWriterLockSlim();
Expand All @@ -282,6 +284,7 @@ public Loader(IMongoDatabase database, string imageCollection, string seriesColl
_statsLock = new object();
_imageStore = database.GetCollection<BsonDocument>(imageCollection);
_seriesStore = database.GetCollection<SeriesMessage>(seriesCollection);
_fileSystem = fileSystem ?? new FileSystem();
}

/// <summary>
Expand All @@ -290,13 +293,13 @@ public Loader(IMongoDatabase database, string imageCollection, string seriesColl
/// <param name="fi">DICOM file or archive of DICOM files to load</param>
/// <param name="ct">Cancellation token</param>
/// <exception cref="ApplicationException"></exception>
private void Process(FileInfo fi, CancellationToken ct)
private void Process(IFileInfo fi, CancellationToken ct)
{
ct.ThrowIfCancellationRequested();
var dName = fi.DirectoryName ?? throw new ApplicationException($"No parent directory for '{fi.FullName}'");
var bBuffer = new byte[132];
var buffer = new Span<byte>(bBuffer);
using (var fileStream = File.OpenRead(fi.FullName))
using (var fileStream = fi.OpenRead())
{
if (fileStream.Read(buffer) == 132 && buffer[128..].SequenceEqual(_dicomMagic))
{
Expand Down Expand Up @@ -429,7 +432,7 @@ private bool ExistingEntry(string filename)
/// <returns></returns>
public ValueTask Load(string filename, CancellationToken ct)
{
if (!File.Exists(filename))
if (!_fileSystem.File.Exists(filename))
{
Console.WriteLine($@"{filename} does not exist, skipping");
return ValueTask.CompletedTask;
Expand All @@ -442,7 +445,7 @@ public ValueTask Load(string filename, CancellationToken ct)

try
{
Process(new FileInfo(filename), ct);
Process(_fileSystem.FileInfo.New(filename), ct);
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static int Main(IEnumerable<string> args, IFileSystem? fileSystem = null)

try
{
return SmiCliInit.ParseAndRun<DynamicRulesTesterCliOptions>(args, typeof(DynamicRulesTester), OnParse);
return SmiCliInit.ParseAndRun<DynamicRulesTesterCliOptions>(args, typeof(DynamicRulesTester), OnParse, _fileSystem);
}
catch (Exception e)
{
Expand All @@ -31,7 +31,7 @@ public static int Main(IEnumerable<string> args, IFileSystem? fileSystem = null)
}
}

private static int OnParse(GlobalOptions _, DynamicRulesTesterCliOptions cliOptions)
private static int OnParse(GlobalOptions _, IFileSystem fileSystem, DynamicRulesTesterCliOptions cliOptions)
{
var dynamicRejector = new DynamicRejector(cliOptions.DynamicRulesFile, _fileSystem);

Expand Down
10 changes: 6 additions & 4 deletions src/SmiServices/Applications/ExtractImages/ExtractImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,30 @@
using SmiServices.Common.Options;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO.Abstractions;


namespace SmiServices.Applications.ExtractImages
{
[ExcludeFromCodeCoverage]
public static class ExtractImages
{
public static int Main(IEnumerable<string> args)
public static int Main(IEnumerable<string> args, IFileSystem? fileSystem = null)
{
int ret = SmiCliInit
.ParseAndRun<ExtractImagesCliOptions>(
args,
typeof(ExtractImages),
OnParse
OnParse,
fileSystem ?? new FileSystem()
);
return ret;
}

private static int OnParse(GlobalOptions globals, ExtractImagesCliOptions parsedOptions)
private static int OnParse(GlobalOptions globals, IFileSystem fileSystem, ExtractImagesCliOptions parsedOptions)
{
var bootstrapper =
new MicroserviceHostBootstrapper(() => new ExtractImagesHost(globals, parsedOptions));
new MicroserviceHostBootstrapper(() => new ExtractImagesHost(globals, parsedOptions, fileSystem));
int ret = bootstrapper.Main();
return ret;
}
Expand Down
22 changes: 10 additions & 12 deletions src/SmiServices/Applications/ExtractImages/ExtractImagesHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ namespace SmiServices.Applications.ExtractImages
{
public class ExtractImagesHost : MicroserviceHost
{
private readonly IFileSystem _fileSystem;

private readonly string _csvFilePath;

private readonly IExtractionMessageSender _extractionMessageSender;
Expand All @@ -26,37 +24,37 @@ public class ExtractImagesHost : MicroserviceHost
public ExtractImagesHost(
GlobalOptions globals,
ExtractImagesCliOptions cliOptions,
IFileSystem? fileSystem = null,
IExtractionMessageSender? extractionMessageSender = null,
IMessageBroker? messageBroker = null,
IFileSystem? fileSystem = null,
bool threaded = false
)
: base(
globals,
fileSystem ?? new FileSystem(),
messageBroker,
threaded
)
{
ExtractImagesOptions? options = Globals.ExtractImagesOptions ?? throw new ArgumentException(nameof(Globals.ExtractImagesOptions));
_fileSystem = fileSystem ?? new FileSystem();

string extractRoot = Globals.FileSystemOptions?.ExtractRoot ?? throw new ArgumentException("Some part of Globals.FileSystemOptions.ExtractRoot was null");
if (!_fileSystem.Directory.Exists(extractRoot))
if (!FileSystem.Directory.Exists(extractRoot))
throw new DirectoryNotFoundException($"Could not find the extraction root '{extractRoot}'");

_csvFilePath = cliOptions.CohortCsvFile;
if (string.IsNullOrWhiteSpace(_csvFilePath))
throw new ArgumentNullException(nameof(cliOptions));
if (!_fileSystem.File.Exists(_csvFilePath))
if (!FileSystem.File.Exists(_csvFilePath))
throw new FileNotFoundException($"Could not find the cohort CSV file '{_csvFilePath}'");

// TODO(rkm 2021-04-01) Now that all the extraction path code is in C#, we would benefit from refactoring it all out
// to a helper class to support having multiple configurations (and probably prevent some bugs)
string extractionName = _fileSystem.Path.GetFileNameWithoutExtension(_csvFilePath);
string extractionDir = _fileSystem.Path.Join(cliOptions.ProjectId, "extractions", extractionName);
_absoluteExtractionDir = _fileSystem.Path.Join(extractRoot, extractionDir);
string extractionName = FileSystem.Path.GetFileNameWithoutExtension(_csvFilePath);
string extractionDir = FileSystem.Path.Join(cliOptions.ProjectId, "extractions", extractionName);
_absoluteExtractionDir = FileSystem.Path.Join(extractRoot, extractionDir);

if (_fileSystem.Directory.Exists(_absoluteExtractionDir))
if (FileSystem.Directory.Exists(_absoluteExtractionDir))
throw new DirectoryNotFoundException($"Extraction directory already exists '{_absoluteExtractionDir}'");

if (extractionMessageSender == null)
Expand All @@ -69,7 +67,7 @@ public ExtractImagesHost(
cliOptions,
extractionRequestProducer,
extractionRequestInfoProducer,
_fileSystem,
FileSystem,
extractRoot,
extractionDir,
new DateTimeProvider(),
Expand All @@ -85,7 +83,7 @@ public ExtractImagesHost(

public override void Start()
{
var parser = new CohortCsvParser(_fileSystem);
var parser = new CohortCsvParser(FileSystem);
(ExtractionKey extractionKey, List<string> idList) = parser.Parse(_csvFilePath);

_extractionMessageSender.SendMessages(extractionKey, idList);
Expand Down
3 changes: 2 additions & 1 deletion src/SmiServices/Applications/Setup/EnvironmentProbe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Abstractions;
using System.Linq;
using System.Text;

Expand Down Expand Up @@ -118,7 +119,7 @@ public EnvironmentProbe(string? yamlFile)
if (string.IsNullOrWhiteSpace(yamlFile))
throw new Exception("You have not yet entered a path for yaml file");

Options = new GlobalOptionsFactory().Load("Setup", yamlFile);
Options = new GlobalOptionsFactory().Load("Setup", new FileSystem(), yamlFile);
DeserializeYaml = new CheckEventArgs("Deserialized Yaml File", CheckResult.Success);
}
catch (Exception ex)
Expand Down
Loading
Loading