Merge pull request #2 from dnutiu/uwp-testing
Overload ICompressor and IMetadataRemover and accept a Stream
This commit is contained in:
commit
1cec529c7b
15 changed files with 166 additions and 46 deletions
|
@ -7,14 +7,17 @@ using Xunit;
|
|||
|
||||
namespace ConsoleInterface.Tests;
|
||||
|
||||
public class TestSimpleOutputSink
|
||||
public class TestDirectoryOutputSink
|
||||
{
|
||||
private readonly string? _testsProjectDirectory;
|
||||
|
||||
public TestSimpleOutputSink()
|
||||
public TestDirectoryOutputSink()
|
||||
{
|
||||
_testsProjectDirectory = Environment.GetEnvironmentVariable("IMAGE_CORE_TESTS");
|
||||
if (_testsProjectDirectory == null) throw new Exception("Environment variable IMAGE_CORE_TESTS is not set!");
|
||||
if (_testsProjectDirectory == null)
|
||||
{
|
||||
throw new Exception("Environment variable IMAGE_CORE_TESTS is not set!");
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
@ -24,14 +27,14 @@ public class TestSimpleOutputSink
|
|||
[InlineData("dir", "asd", @"dir\asd.jpg")]
|
||||
public void TestGetOutputPath(string directory, string file, string expectedPath)
|
||||
{
|
||||
var sink = SimpleOutputSink.Create(directory);
|
||||
var sink = DirectoryOutputSink.Create(directory);
|
||||
Assert.Equal(expectedPath, sink.GetOutputPath(file));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestGetOutputPathNull()
|
||||
{
|
||||
var sink = SimpleOutputSink.Create("directory");
|
||||
var sink = DirectoryOutputSink.Create("directory");
|
||||
Assert.Throws<ArgumentException>(() => sink.GetOutputPath(""));
|
||||
}
|
||||
|
||||
|
@ -39,7 +42,7 @@ public class TestSimpleOutputSink
|
|||
public void TestSave()
|
||||
{
|
||||
// Setup
|
||||
var sink = SimpleOutputSink.Create("directory");
|
||||
var sink = DirectoryOutputSink.Create("directory");
|
||||
var metadataRemoverMock = new Mock<IMetadataRemover>();
|
||||
metadataRemoverMock.Setup(i => i.GetImagePath()).Returns("alo.wtf");
|
||||
|
||||
|
@ -47,7 +50,8 @@ public class TestSimpleOutputSink
|
|||
sink.Save(metadataRemoverMock.Object);
|
||||
|
||||
// Assert
|
||||
metadataRemoverMock.Verify(i => i.CleanImage("directory\\alo.jpg"));
|
||||
metadataRemoverMock.Verify(i => i.CleanImage());
|
||||
metadataRemoverMock.Verify(i => i.SaveImage("directory\\alo.jpg"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -55,7 +59,7 @@ public class TestSimpleOutputSink
|
|||
{
|
||||
// Setup
|
||||
Debug.Assert(_testsProjectDirectory != null, nameof(_testsProjectDirectory) + " != null");
|
||||
var sink = SimpleOutputSink.Create(Path.Combine(_testsProjectDirectory, "test_pictures"));
|
||||
var sink = DirectoryOutputSink.Create(Path.Combine(_testsProjectDirectory, "test_pictures"));
|
||||
var metadataRemoverMock = new Mock<IMetadataRemover>();
|
||||
var sourceFileName = Path.Combine(_testsProjectDirectory, "test_pictures\\IMG_0138.HEIC");
|
||||
metadataRemoverMock.Setup(i => i.GetImagePath()).Returns(sourceFileName);
|
||||
|
@ -64,6 +68,7 @@ public class TestSimpleOutputSink
|
|||
sink.Save(metadataRemoverMock.Object);
|
||||
|
||||
// Assert
|
||||
metadataRemoverMock.Verify(i => i.CleanImage(It.IsAny<string>()), Times.Never);
|
||||
metadataRemoverMock.Verify(i => i.CleanImage(), Times.Never);
|
||||
metadataRemoverMock.Verify(i => i.SaveImage(It.IsAny<string>()), Times.Never);
|
||||
}
|
||||
}
|
|
@ -14,7 +14,10 @@ public class TestLocalFileBrowser
|
|||
public TestLocalFileBrowser()
|
||||
{
|
||||
_testsProjectDirectory = Environment.GetEnvironmentVariable("IMAGE_CORE_TESTS");
|
||||
if (_testsProjectDirectory == null) throw new Exception("Environment variable IMAGE_CORE_TESTS is not set!");
|
||||
if (_testsProjectDirectory == null)
|
||||
{
|
||||
throw new Exception("Environment variable IMAGE_CORE_TESTS is not set!");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -39,6 +42,8 @@ public class TestLocalFileBrowser
|
|||
|
||||
Assert.NotEmpty(filePathsList);
|
||||
for (var i = 0; i < filePathsList.Count; i++)
|
||||
{
|
||||
Assert.Equal(expectedFileNames[i], Path.GetFileName(filePathsList[i]));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,25 +8,30 @@ using Microsoft.Extensions.Logging.Abstractions;
|
|||
namespace ConsoleInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// SimpleOutputFormatter keeps the original file name of the image when formatting it.
|
||||
/// SimpleOutputFormatter also saves all the file names into a new directory.
|
||||
/// DirectoryOutputSink keeps the original file name of the image when formatting it.
|
||||
/// DirectoryOutputSink also saves all the file names into a new directory.
|
||||
/// path.
|
||||
/// </summary>
|
||||
public class SimpleOutputSink : IOutputSink
|
||||
public class DirectoryOutputSink : IOutputSink
|
||||
{
|
||||
public static ILogger Logger = NullLogger.Instance;
|
||||
private readonly string _outputDirectory;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of SimpleOutputFormatter.
|
||||
/// Creates an instance of DirectoryOutputSink.
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">The output directory.</param>
|
||||
public SimpleOutputSink(string outputDirectory)
|
||||
public DirectoryOutputSink(string outputDirectory)
|
||||
{
|
||||
if (outputDirectory.Equals(""))
|
||||
{
|
||||
outputDirectory = ".";
|
||||
}
|
||||
else
|
||||
{
|
||||
FileSystemHelpers.CreateDestinationDirectory(outputDirectory);
|
||||
}
|
||||
|
||||
_outputDirectory = outputDirectory;
|
||||
}
|
||||
|
||||
|
@ -41,7 +46,8 @@ namespace ConsoleInterface
|
|||
}
|
||||
|
||||
// Save the image under the same name in the new directory.
|
||||
metadataRemover.CleanImage(newFilePath);
|
||||
metadataRemover.CleanImage();
|
||||
metadataRemover.SaveImage(newFilePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -54,7 +60,9 @@ namespace ConsoleInterface
|
|||
{
|
||||
Logger.LogDebug($"KeepFilenameFormatter - {_outputDirectory} - {initialFilePath}");
|
||||
if (string.IsNullOrEmpty(initialFilePath))
|
||||
{
|
||||
throw new ArgumentException("The output file path cannot be null or empty!");
|
||||
}
|
||||
|
||||
var fileName = Path.GetFileName(initialFilePath).Split('.')[0];
|
||||
var path = Path.Combine(_outputDirectory, $"{fileName}.jpg");
|
||||
|
@ -62,12 +70,12 @@ namespace ConsoleInterface
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of OriginalFilenameFileOutputPathFormatter.
|
||||
/// Creates an instance of DirectoryOutputSink.
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">The output directory.</param>
|
||||
public static SimpleOutputSink Create(string outputDirectory)
|
||||
public static DirectoryOutputSink Create(string outputDirectory)
|
||||
{
|
||||
return new SimpleOutputSink(outputDirectory);
|
||||
return new DirectoryOutputSink(outputDirectory);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,11 @@ namespace ConsoleInterface
|
|||
/// <param name="directoryPath">The destination directory's path.</param>
|
||||
public static void CreateDestinationDirectory(string directoryPath)
|
||||
{
|
||||
if (Directory.Exists(directoryPath)) return;
|
||||
if (Directory.Exists(directoryPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.LogWarning("Output directory does not exist. Creating.");
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace ConsoleInterface
|
|||
private static void RunOptions(ProgramOptions options)
|
||||
{
|
||||
SetupLogging(options.LogLevel);
|
||||
var outputFormatter = SimpleOutputSink.Create(options.DestinationDirectory);
|
||||
var outputFormatter = DirectoryOutputSink.Create(options.DestinationDirectory);
|
||||
var executor = TaskExecutor.Create(new TaskExecutorOptions
|
||||
{
|
||||
EnableCompression = options.CompressFiles is true,
|
||||
|
@ -105,8 +105,8 @@ namespace ConsoleInterface
|
|||
// File Retriever
|
||||
LocalFileBrowser.Logger = _loggerFactory.CreateLogger(nameof(LocalFileBrowser));
|
||||
// FileName formatter
|
||||
SimpleOutputSink.Logger =
|
||||
_loggerFactory.CreateLogger(nameof(SimpleOutputSink));
|
||||
DirectoryOutputSink.Logger =
|
||||
_loggerFactory.CreateLogger(nameof(DirectoryOutputSink));
|
||||
FileSystemHelpers.Logger = _loggerFactory.CreateLogger(nameof(FileSystemHelpers));
|
||||
Logger.LogTrace("SetupLogging - exit");
|
||||
}
|
||||
|
|
|
@ -51,7 +51,11 @@ namespace ConsoleInterface
|
|||
$"Cleaning {filePath}, compression {_options.EnableCompression}, outputFormatter {nameof(_options.OutputSink)}.");
|
||||
|
||||
ICompressor compressor = NullCompressor.Instance;
|
||||
if (_options.EnableCompression) compressor = LosslessCompressor.Instance;
|
||||
if (_options.EnableCompression)
|
||||
{
|
||||
compressor = LosslessCompressor.Instance;
|
||||
}
|
||||
|
||||
var imageMagick = new MagickImage(filePath);
|
||||
IMetadataRemover metadataRemover = new ExifRemoverAndCompressor(imageMagick, compressor);
|
||||
return outputSink.Save(metadataRemover);
|
||||
|
|
|
@ -5,7 +5,7 @@ using Xunit;
|
|||
|
||||
namespace ImageCore.Tests
|
||||
{
|
||||
public class TestMetadataRemover
|
||||
public class TestExifRemoverAndCompressor
|
||||
{
|
||||
[Fact]
|
||||
public void TestExifRemoverAndCompressorCleanImage()
|
||||
|
@ -16,7 +16,8 @@ namespace ImageCore.Tests
|
|||
var metadataRemover = new ExifRemoverAndCompressor(magicImageMock.Object, compressorMock.Object);
|
||||
|
||||
// Test
|
||||
metadataRemover.CleanImage("path");
|
||||
metadataRemover.CleanImage();
|
||||
metadataRemover.SaveImage("path");
|
||||
|
||||
// Assert
|
||||
magicImageMock.Verify(i => i.RemoveProfile("exif"));
|
|
@ -34,22 +34,19 @@ namespace ImageCore.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void TestNullCompressor_Compress()
|
||||
public void TestLosslessCompressor_Compress_Stream()
|
||||
{
|
||||
ICompressor compressor = new NullCompressor();
|
||||
ICompressor compressor = new LosslessCompressor();
|
||||
var sourceFileName = Path.Combine(_testsProjectDirectory, "test_pictures/IMG_0138.HEIC");
|
||||
var destinationFileName = Path.GetTempFileName();
|
||||
File.Copy(sourceFileName, destinationFileName, true);
|
||||
compressor.Compress(destinationFileName);
|
||||
|
||||
var originalFile = File.Open(sourceFileName, FileMode.Open);
|
||||
var compressedFile = File.Open(destinationFileName, FileMode.Open);
|
||||
var destinationFileHandle = File.Open(destinationFileName, FileMode.Open);
|
||||
var lengthBeforeCompression = destinationFileHandle.Length;
|
||||
|
||||
Assert.True(compressedFile.Length == originalFile.Length);
|
||||
compressor.Compress(destinationFileHandle);
|
||||
|
||||
originalFile.Close();
|
||||
compressedFile.Close();
|
||||
File.Delete(destinationFileName);
|
||||
Assert.True(destinationFileHandle.Length < lengthBeforeCompression);
|
||||
}
|
||||
}
|
||||
}
|
37
ImageCore.Tests/TestNullCompressor.cs
Normal file
37
ImageCore.Tests/TestNullCompressor.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Image.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace ImageCore.Tests
|
||||
{
|
||||
public class TestNullCompressor
|
||||
{
|
||||
private readonly string _testsProjectDirectory;
|
||||
|
||||
public TestNullCompressor()
|
||||
{
|
||||
_testsProjectDirectory = Environment.GetEnvironmentVariable("IMAGE_CORE_TESTS");
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void TestNullCompressor_Compress()
|
||||
{
|
||||
ICompressor compressor = new NullCompressor();
|
||||
var sourceFileName = Path.Combine(_testsProjectDirectory, "test_pictures/IMG_0138.HEIC");
|
||||
var destinationFileName = Path.GetTempFileName();
|
||||
File.Copy(sourceFileName, destinationFileName, true);
|
||||
compressor.Compress(destinationFileName);
|
||||
|
||||
var originalFile = File.Open(sourceFileName, FileMode.Open);
|
||||
var compressedFile = File.Open(destinationFileName, FileMode.Open);
|
||||
|
||||
Assert.True(compressedFile.Length == originalFile.Length);
|
||||
|
||||
originalFile.Close();
|
||||
compressedFile.Close();
|
||||
File.Delete(destinationFileName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using ImageMagick;
|
||||
using System.IO;
|
||||
using ImageMagick;
|
||||
|
||||
namespace Image.Core
|
||||
{
|
||||
|
@ -22,12 +23,19 @@ namespace Image.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleans the images and compresses it.
|
||||
/// Cleans the image.
|
||||
/// </summary>
|
||||
/// <param name="newFilePath">The file path to save the clean image.</param>
|
||||
public void CleanImage(string newFilePath)
|
||||
public void CleanImage()
|
||||
{
|
||||
_magickImage.RemoveProfile("exif");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the image under a new file path.
|
||||
/// </summary>
|
||||
/// <param name="newFilePath">The new path of the image.</param>
|
||||
public void SaveImage(string newFilePath)
|
||||
{
|
||||
_magickImage.Write(newFilePath);
|
||||
_compressor.Compress(newFilePath);
|
||||
}
|
||||
|
@ -37,5 +45,15 @@ namespace Image.Core
|
|||
{
|
||||
return _magickImage.FileName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the image.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream.</param>
|
||||
public void SaveImage(Stream stream)
|
||||
{
|
||||
_magickImage.Write(stream);
|
||||
_compressor.Compress(stream);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
namespace Image.Core
|
||||
using System.IO;
|
||||
|
||||
namespace Image.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// ICompressor is an interface for implementing image compressors.
|
||||
|
@ -10,5 +12,11 @@
|
|||
/// </summary>
|
||||
/// <param name="fileName">The file name of the image to be compressed.</param>
|
||||
void Compress(string fileName);
|
||||
|
||||
/// <summary>
|
||||
/// The method compresses an image in place.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream of the image to be compressed.</param>
|
||||
void Compress(Stream stream);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
namespace Image.Core
|
||||
using System.IO;
|
||||
|
||||
namespace Image.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for implementing metadata removers.
|
||||
|
@ -6,10 +8,21 @@
|
|||
public interface IMetadataRemover
|
||||
{
|
||||
/// <summary>
|
||||
/// Cleans an image and saves it under a new path.
|
||||
/// Cleans an image.
|
||||
/// </summary>
|
||||
void CleanImage();
|
||||
|
||||
/// <summary>
|
||||
/// Saves an image under a new file path.
|
||||
/// </summary>
|
||||
/// <param name="newFilePath">The file path to save the clean image.</param>
|
||||
void CleanImage(string newFilePath);
|
||||
void SaveImage(string newFilePath);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the image.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream.</param>
|
||||
void SaveImage(Stream stream);
|
||||
|
||||
/// <summary>
|
||||
/// GetImagePath gets the current image path on the filesystem.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using ImageMagick;
|
||||
using System.IO;
|
||||
using ImageMagick;
|
||||
|
||||
namespace Image.Core
|
||||
{
|
||||
|
@ -22,5 +23,13 @@ namespace Image.Core
|
|||
{
|
||||
_imageOptimizer.LosslessCompress(fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc />
|
||||
/// </summary>
|
||||
public void Compress(Stream stream)
|
||||
{
|
||||
_imageOptimizer.LosslessCompress(stream);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
namespace Image.Core
|
||||
using System.IO;
|
||||
|
||||
namespace Image.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Does nothing. Using this Compressor will have no effect.
|
||||
|
@ -13,5 +15,9 @@
|
|||
public void Compress(string fileName)
|
||||
{
|
||||
}
|
||||
|
||||
public void Compress(Stream stream)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,5 +6,10 @@
|
|||
</AssemblyExplorer></s:String>
|
||||
|
||||
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=761234b5_002D46ba_002D4312_002Dab60_002Dd15d5d83a61a/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="TestGetFilenamesFromPath" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||
<Or>
|
||||
<Project Location="C:\Users\nutiu\RiderProjects\ImgMetadataRemover\ImageCore.Tests" Presentation="&lt;ImageCore.Tests&gt;" />
|
||||
<TestAncestor>
|
||||
<TestId>xUnit::B915AC83-B6E9-4E0A-BA88-915F629F57C8::net6.0::ConsoleInterface.Tests.TestSimpleOutputSink</TestId>
|
||||
</TestAncestor>
|
||||
</Or>
|
||||
</SessionState></s:String></wpf:ResourceDictionary>
|
Loading…
Reference in a new issue