Merge ImageResizer into master (#1469)

* Import Image Resizer for Windows

* getting code analysis and stylecop hooked in

* upgrading to 4.7.2

* adding copyright

* getting stuff to work

headers and trailing commas

adding braces

updated encoder

* Revert "getting stuff to work"

This reverts commit 5310866120.

* update to .net 4.7.2

* access modifier

* zero errors

* Fixed unit tests not running issue

* Fixed ImageResizer.Test stylecop warning

* Formatted ShellExtensions project with clang-format

* Fixed annotation warnings

* Suppressed 6031 and 26812 warnings for specific lines

* Shifting ImageResizer projects to PowerToys solution (#1054)

* Shifted ImageResizer projects to PowerToys solution: Builds, all tests pass, ImageResizer C# project works independently

* Deleted extra files

* Deleted nuget config file and fixed code analysis paths

* Convert ImageResizer to a PowerToy (#1073)

* Updated vcxproj file with common project references and cpp version flags

* Added module template code to dllmain and updated headers for successful build

* Removed unnecessary include

* Added dll to runner and add fixes to show up in PT Settings

* Added settings file

* Added support for enabling/disabling based on PowerRename codebase

* Fixed missing braces

* Fixed call_custom_action

* Add ImageResizer to msi installer (dev/imageResizer) (#1094)

* Updated vcxproj file with common project references and cpp version flags

* Added module template code to dllmain and updated headers for successful build

* Removed unnecessary include

* Added dll to runner and add fixes to show up in PT Settings

* Added settings file

* Added support for enabling/disabling based on PowerRename codebase

* Fixed solution file configurations

* Removed Any CPU from ImageResizer csprojs

* Renamed registry writing and removed build time registry addition

* Added ImageResizer installation details to msi

* Fixed comment on conditions to close explorer.exe

* Sync dev/imageResizer with master (#1105)

* tweaking language

* adjusting elevated permission verbiage to match Windows

* npm audit fix to update stuff

* slight bump for fabric ui

* Remove unwanted files (#1037)

Add temp build files to gitignore

* Ensure previous search and replace texts are evaluated and updated in the UI at startup (#1043)

Ensure stored settings get evaluated after initial enumeration

There was a bug where the list view was not getting updated with the results of the search and replace on launch when we are using a stored search or replace text from a previous session.

* adding fancy zone opacity setting, enhancement #631 (#1008)

* adding fancy zone opacity setting, enhancement #631

* applying zone opacity setting to all zones during zone selection

* changing opacity setting to percentage

* runner: show message box when restarting with different elevation fails (#1061)

Also make the message box appear on top of the settings window.

* Fix misaligned display of zones in layout priview and grid editor (#1010)

Fix misaligned display of zones in layout preview and grid editor

* MSIX: Extract MSIX building functionality from msix_reinstall.ps1 to a separate script (#1068)

* MSIX: label PowerToys as Preview (#1090)

* MSIX: Code sign msixbundle (#1093)

* Update to MSIX README.md (#1095)

* Update README.md

few adjustments

* Update README.md

* Update README.md

* adding in privacy statement, removing About in dialog (#1087)

* adding in privacy statement, removing About in dialog

* added Preview

* Revert "Fix misaligned display of zones in layout priview and grid editor (#1010)" (#1097)

This reverts commit d03690cffd.

* Fix reversed order of zones in layout (#1071)

* Shifted three functions to common (#1101)

Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: Enrico Giordani <enricogior@users.noreply.github.com>
Co-authored-by: Chris Davis <chrisdavis@outlook.com>
Co-authored-by: Yosef Durr <yodurr@microsoft.com>
Co-authored-by: Bartosz Sosnowski <bzoz@users.noreply.github.com>
Co-authored-by: vldmr11080 <57061786+vldmr11080@users.noreply.github.com>
Co-authored-by: yuyoyuppe <yuyoyuppe@users.noreply.github.com>

* Revert "Sync dev/imageResizer with master (#1105)"

This reverts commit db7f15541f.

* Added icon to Resize pictures context menu entry (dev/imageResizer) (#1113)

* Updated vcxproj file with common project references and cpp version flags

* Added module template code to dllmain and updated headers for successful build

* Removed unnecessary include

* Added dll to runner and add fixes to show up in PT Settings

* Added settings file

* Added support for enabling/disabling based on PowerRename codebase

* Fixed solution file configurations

* Removed Any CPU from ImageResizer csprojs

* Renamed registry writing and removed build time registry addition

* Added ImageResizer installation details to msi

* Shifted to MII, TODO: Fix position

* Incorporated ImageResizer Icon in context menu entry

* Fixed typo

* Merged with dev/imageResizer

* Renamed Advanced Options to Settings and removed About tab (dev/imageResizer) (#1123)

* Removed about tab, renamed advanced opt to settings, changed assembly info

* Restored Resource designer file

* Reverted changes on AssemblyInfo

* MSI: Fix ImageResizer menu item position (dev/imageResizer) (#1114)

* Updated vcxproj file with common project references and cpp version flags

* Added module template code to dllmain and updated headers for successful build

* Removed unnecessary include

* Added dll to runner and add fixes to show up in PT Settings

* Added settings file

* Added support for enabling/disabling based on PowerRename codebase

* Fixed solution file configurations

* Removed Any CPU from ImageResizer csprojs

* Renamed registry writing and removed build time registry addition

* Added ImageResizer installation details to msi

* Shifted to MII, TODO: Fix position

* Incorporated ImageResizer Icon in context menu entry

* Changed registry entries to SystemFileAssociations and added index changes in InsertMenuItem

* Fixed extra newline

* Fixed merge conflict

* Refactor ImageResizer code base naming to match PowerRename (#1121)

* Created empty README file

* Renamed dll project

* Removed ShellExtensions references in src

* Fixed ImageResizerUI assembly name and added changes to MSI

* added the helper functions

* localized dllmain powerrename

* localized powerRenameExt

* localized the settings file

* built the proj

* Modified resourceIDs for strings in the table

* added common as a reference project

* Removed get_res_string_wchar and used the get_resource_string() function instead which returns a wstring typecast into wchar*

* Added new lines to the end of the file

* Removed string resources from the settings.cpp file

* rebuilt project PowerRename

* moved app name to constructor to init only once

* updated formatting of common.cpp

* reverting formatting of files

* Removed some IDs from resource file. Changed SHIFT to Shift

* Localizing C# Project of FancyZones (FancyZonesEditor) (#199) (#1122)

* removed hardcoded strings from CanvasEditorWindow.xaml

* removed hardcoded strings from GridEditorWindow.xaml

* loc

* Localized MainWindow

* reverting MainWindow.xaml as it is not rendering the window as expected

* Changed the resource settings from internal to public

* the culture is set based on the culture of the system UI set in the system settings

* Removed the french resource files used for testing

* Localized canvasWindow and mainwindow

* Removed setting the UI culture explicitly as it would be implicitly set to the culture of system UI

* Removed redundant header file

* Localize the Shortcut guide PowerToy (#199) (#1126)

* Localized shortcut_guide.cpp

* localized overlay_window.cpp

* formatting changes

* Localize overlay window

* removed the README link from the set of localized resources

* Typo: changed upper to lower

* Localize C++ Projects of FancyZones (#1130)

* localized dllmain.cpp  of fancyzones project

* localized FancyZones.cpp

* format fancyzones.rc file

* Moved SuperFancyZones back to being a string instead of having it in the resource file as it is the window class name

* reverted changes for window name

* Formatted fancyzones rc file

* Align zone dimensions from layout preview with those from grid editor (#1115)

* MSIX: add a dedicated .rc for UWPUI which joins both UI and DLL .rc's (#1139)

* Runner: fix restarting with same elevation (#1133)

* MSIX: reinstall script uses bundle instead of .msi to be able to reinstall in all cases

* Telemetry: add WebView init failure errors

* Settings: initialize COM security to allow communication between elevated Settings and WebView

* Common: implement on_scope_exit helper and typed_storage

* Changes for #1140 and #569 (#1152)

* MSIX build instructions adjustmnet (#1170)

* MSIX: hide the "Run at Startup" option if running as packaged

* MSIX: update identity name and publisher (#1176)

* Runner: fix startup task state setting for MSIX (#1181)

* Add ImageResizer to MSIX installer and make the code MSIX-compatible (#1219)

* Removed ImageResizer.exe location registry key

* Added working resize pictures to MSIX context menu without icon

* Fixed missing icon on MSIX build

* Added comments

* Changed to single context handler entry

* Made changes as per PR comments

* Localize ImageResizer (#1261)

* Removed hardcoded strings

* Added resource dlls to MSIX installer

* Save ImageResizer settings in JSON format (#1258)

* Combined settings files

* Added JSON settings functionality in PowerToys format with thread safety

* Reverting changes to csproj file

* Removed settings.settings and designer file and added target sdk tools to fix warning

* Added NewtonSoft Json package

* Added 3 tests

* Added propertychanged test

* Removed unused libraries

* Removed additional allocation statements in test

* Added comments on test

* Added one-time setup code

* Added Newtonsoft.Json.dll to MSI and MSIX installer

* Fixed copyright header

* Fixed folder location in MSIX

* Renamed jsonMutex to _jsonMutex

* Fixed line endings

* Created private setup functions and added Arrange, Act, Assert comments

* Created private setup functions and added Arrange, Act, Assert comments

* Suppressed copyright warning on AppFixture and enabled treat warnings as errors

* Added comments on Reload/AppFixture and added constructor andispose

* Added telemetry to ImageResizer Shell Extension code (dev/imageResizer) (#1272)

* Added telemetry to C++ ImageResizerExt

* Added Register and unregister calls

* Changed default enable setting

* Set startup location to center of the screen (ImageResizer) (#1452)

* Added ImageResizer resources.dlls to the MSI installer (#1448)

* Implemented fix for foreground issue for ImageResizer (#1434)

* Fixed conflict in installer README.md file

* Fixed conflict in bundle.js

* Auto-generate AssemblyInfo in ImageResizer (#1467)

* Updated assembly info

* Added auto-generation of AssemblyInfo.cs

* Fixed minor issues

* Remove the  License file since Notice.md have been added

* Fix errors due to resolving merge conflicts

Co-authored-by: Brice Lambson <brice@bricelam.net>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: Arjun Balgovind <arbalgov@microsoft.com>
Co-authored-by: Enrico Giordani <enricogior@users.noreply.github.com>
Co-authored-by: Chris Davis <chrisdavis@outlook.com>
Co-authored-by: Yosef Durr <yodurr@microsoft.com>
Co-authored-by: Bartosz Sosnowski <bzoz@users.noreply.github.com>
Co-authored-by: vldmr11080 <57061786+vldmr11080@users.noreply.github.com>
Co-authored-by: yuyoyuppe <yuyoyuppe@users.noreply.github.com>
Co-authored-by: Alekhya Kommuru <alkommur@microsoft.com>
Co-authored-by: Alekhya <reddykalekhya@gmail.com>
Co-authored-by: yuyoyuppe <a.yuyoyuppe@gmail.com>
Co-authored-by: Udit Singh <udsing@microsoft.com>
This commit is contained in:
Arjun Balgovind
2020-03-12 12:02:34 -04:00
committed by GitHub
parent 7f12288b2c
commit d84cc370c9
114 changed files with 13436 additions and 10 deletions

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
</configuration>

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
<ProjectGuid>{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ImageResizer</RootNamespace>
<AssemblyName>ImageResizer.Test</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<CodeAnalysisRuleSet>..\..\..\codeAnalysis\Rules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<CodeAnalysisRuleSet>..\..\..\codeAnalysis\Rules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="System" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ui\ImageResizerUI.csproj">
<Project>{2be46397-4dfa-414c-9bd4-41e4bbf8cb34}</Project>
<Name>ImageResizerUI</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
<Link>StyleCop.json</Link>
</AdditionalFiles>
<None Include="App.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<Compile Include="..\codeAnalysis\GlobalSuppressions.cs">
<Link>GlobalSuppressions.cs</Link>
</Compile>
<Compile Include="Models\CustomSizeTests.cs" />
<Compile Include="Models\ResizeSizeTests.cs" />
<Compile Include="Models\ResizeBatchTests.cs" />
<Compile Include="Models\ResizeOperationTests.cs" />
<Compile Include="Properties\AppFixture.cs" />
<Compile Include="Properties\SettingsTests.cs" />
<Compile Include="Test\AssertEx.cs" />
<Compile Include="Test\BitmapSourceExtensions.cs" />
<Compile Include="Test\TestDirectory.cs" />
<Compile Include="Views\TimeRemainingConverterTests.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Test.gif">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Test.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Test.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Test.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="TestPortrait.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Moq">
<Version>4.13.1</Version>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers">
<Version>1.1.118</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.ValueTuple">
<Version>4.5.0</Version>
</PackageReference>
<PackageReference Include="xunit">
<Version>2.4.1</Version>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio">
<Version>2.4.1</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,22 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using ImageResizer.Properties;
using Xunit;
namespace ImageResizer.Models
{
public class CustomSizeTests
{
[Fact]
public void Name_works()
{
var size = new CustomSize();
size.Name = "Ignored";
Assert.Equal(Resources.Input_Custom, size.Name);
}
}
}

View File

@@ -0,0 +1,108 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using Moq;
using Moq.Protected;
using Xunit;
namespace ImageResizer.Models
{
public class ResizeBatchTests
{
private static readonly string EOL = Environment.NewLine;
[Fact]
public void FromCommandLine_works()
{
var standardInput =
"Image1.jpg" + EOL +
"Image2.jpg";
var args = new[]
{
"/d", "OutputDir",
"Image3.jpg",
};
var result = ResizeBatch.FromCommandLine(
new StringReader(standardInput),
args);
Assert.Equal(new List<string> { "Image1.jpg", "Image2.jpg", "Image3.jpg" }, result.Files);
Assert.Equal("OutputDir", result.DestinationDirectory);
}
[Fact]
public void Process_executes_in_parallel()
{
var batch = CreateBatch(_ => Thread.Sleep(50));
batch.Files.AddRange(
Enumerable.Range(0, Environment.ProcessorCount)
.Select(i => "Image" + i + ".jpg"));
var stopwatch = Stopwatch.StartNew();
batch.Process(CancellationToken.None, (_, __) => { });
stopwatch.Stop();
Assert.InRange(stopwatch.ElapsedMilliseconds, 50, 99);
}
[Fact]
public void Process_aggregates_errors()
{
var batch = CreateBatch(file => throw new Exception("Error: " + file));
batch.Files.Add("Image1.jpg");
batch.Files.Add("Image2.jpg");
var errors = batch.Process(CancellationToken.None, (_, __) => { }).ToList();
Assert.Equal(2, errors.Count);
var errorFiles = new List<string>();
foreach (var error in errors)
{
errorFiles.Add(error.File);
Assert.Equal("Error: " + error.File, error.Error);
}
foreach (var file in batch.Files)
{
Assert.Contains(file, errorFiles);
}
}
[Fact]
public void Process_reports_progress()
{
var batch = CreateBatch(_ => { });
batch.Files.Add("Image1.jpg");
batch.Files.Add("Image2.jpg");
var calls = new ConcurrentBag<(int i, double count)>();
batch.Process(
CancellationToken.None,
(i, count) => calls.Add((i, count)));
Assert.Equal(2, calls.Count);
Assert.Contains(calls, c => c.i == 1 && c.count == 2);
Assert.Contains(calls, c => c.i == 2 && c.count == 2);
}
private static ResizeBatch CreateBatch(Action<string> executeAction)
{
var mock = new Mock<ResizeBatch> { CallBase = true };
mock.Protected().Setup("Execute", ItExpr.IsAny<string>()).Callback(executeAction);
return mock.Object;
}
}
}

View File

@@ -0,0 +1,453 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ImageResizer.Properties;
using ImageResizer.Test;
using Xunit;
namespace ImageResizer.Models
{
public class ResizeOperationTests : IDisposable
{
private readonly TestDirectory _directory = new TestDirectory();
[Fact]
public void Execute_copies_frame_metadata()
{
var operation = new ResizeOperation("Test.jpg", _directory, Settings());
operation.Execute();
AssertEx.Image(
_directory.File(),
image => Assert.Equal("Test", ((BitmapMetadata)image.Frames[0].Metadata).Comment));
}
[Fact]
public void Execute_keeps_date_modified()
{
var operation = new ResizeOperation("Test.png", _directory, Settings(s => s.KeepDateModified = true));
operation.Execute();
Assert.Equal(File.GetLastWriteTimeUtc("Test.png"), File.GetLastWriteTimeUtc(_directory.File()));
}
[Fact]
public void Execute_keeps_date_modified_when_replacing_originals()
{
var path = Path.Combine(_directory, "Test.png");
File.Copy("Test.png", path);
var originalDateModified = File.GetLastWriteTimeUtc(path);
var operation = new ResizeOperation(
path,
null,
Settings(
s =>
{
s.KeepDateModified = true;
s.Replace = true;
}));
operation.Execute();
Assert.Equal(originalDateModified, File.GetLastWriteTimeUtc(_directory.File()));
}
[Fact]
public void Execute_replaces_originals()
{
var path = Path.Combine(_directory, "Test.png");
File.Copy("Test.png", path);
var operation = new ResizeOperation(path, null, Settings(s => s.Replace = true));
operation.Execute();
AssertEx.Image(_directory.File(), image => Assert.Equal(96, image.Frames[0].PixelWidth));
}
[Fact]
public void Execute_transforms_each_frame()
{
var operation = new ResizeOperation("Test.gif", _directory, Settings());
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(2, image.Frames.Count);
AssertEx.All(image.Frames, frame => Assert.Equal(96, frame.PixelWidth));
});
}
[Fact]
public void Execute_uses_fallback_encoder()
{
var operation = new ResizeOperation(
"Test.ico",
_directory,
Settings(s => s.FallbackEncoder = new PngBitmapEncoder().CodecInfo.ContainerFormat));
operation.Execute();
Assert.Contains("Test (Test).png", _directory.FileNames);
}
[Fact]
public void Transform_ignores_orientation_when_landscape_to_portrait()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(
x =>
{
x.IgnoreOrientation = true;
x.SelectedSize.Width = 96;
x.SelectedSize.Height = 192;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(192, image.Frames[0].PixelWidth);
Assert.Equal(96, image.Frames[0].PixelHeight);
});
}
[Fact]
public void Transform_ignores_orientation_when_portrait_to_landscape()
{
var operation = new ResizeOperation(
"TestPortrait.png",
_directory,
Settings(
x =>
{
x.IgnoreOrientation = true;
x.SelectedSize.Width = 192;
x.SelectedSize.Height = 96;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(96, image.Frames[0].PixelWidth);
Assert.Equal(192, image.Frames[0].PixelHeight);
});
}
[Fact]
public void Transform_ignores_ignore_orientation_when_auto()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(
x =>
{
x.IgnoreOrientation = true;
x.SelectedSize.Width = 96;
x.SelectedSize.Height = 0;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(96, image.Frames[0].PixelWidth);
Assert.Equal(48, image.Frames[0].PixelHeight);
});
}
[Fact]
public void Transform_ignores_ignore_orientation_when_percent()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(
x =>
{
x.IgnoreOrientation = true;
x.SelectedSize.Width = 50;
x.SelectedSize.Height = 200;
x.SelectedSize.Unit = ResizeUnit.Percent;
x.SelectedSize.Fit = ResizeFit.Stretch;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(96, image.Frames[0].PixelWidth);
Assert.Equal(192, image.Frames[0].PixelHeight);
});
}
[Fact]
public void Transform_honors_shrink_only()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(
x =>
{
x.ShrinkOnly = true;
x.SelectedSize.Width = 288;
x.SelectedSize.Height = 288;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(192, image.Frames[0].PixelWidth);
Assert.Equal(96, image.Frames[0].PixelHeight);
});
}
[Fact]
public void Transform_ignores_shrink_only_when_percent()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(
x =>
{
x.ShrinkOnly = true;
x.SelectedSize.Width = 133.3;
x.SelectedSize.Unit = ResizeUnit.Percent;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(256, image.Frames[0].PixelWidth);
Assert.Equal(128, image.Frames[0].PixelHeight);
});
}
[Fact]
public void Transform_honors_shrink_only_when_auto_height()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(
x =>
{
x.ShrinkOnly = true;
x.SelectedSize.Width = 288;
x.SelectedSize.Height = 0;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image => Assert.Equal(192, image.Frames[0].PixelWidth));
}
[Fact]
public void Transform_honors_shrink_only_when_auto_width()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(
x =>
{
x.ShrinkOnly = true;
x.SelectedSize.Width = 0;
x.SelectedSize.Height = 288;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image => Assert.Equal(96, image.Frames[0].PixelHeight));
}
[Fact]
public void Transform_honors_unit()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(
x =>
{
x.SelectedSize.Width = 1;
x.SelectedSize.Height = 1;
x.SelectedSize.Unit = ResizeUnit.Inch;
}));
operation.Execute();
AssertEx.Image(_directory.File(), image => Assert.Equal(image.Frames[0].DpiX, image.Frames[0].PixelWidth, 0));
}
[Fact]
public void Transform_honors_fit_when_Fit()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(x => x.SelectedSize.Fit = ResizeFit.Fit));
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(96, image.Frames[0].PixelWidth);
Assert.Equal(48, image.Frames[0].PixelHeight);
});
}
[Fact]
public void Transform_honors_fit_when_Fill()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(x => x.SelectedSize.Fit = ResizeFit.Fill));
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(Colors.White, image.Frames[0].GetFirstPixel());
Assert.Equal(96, image.Frames[0].PixelWidth);
Assert.Equal(96, image.Frames[0].PixelHeight);
});
}
[Fact]
public void Transform_honors_fit_when_Stretch()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(x => x.SelectedSize.Fit = ResizeFit.Stretch));
operation.Execute();
AssertEx.Image(
_directory.File(),
image =>
{
Assert.Equal(Colors.Black, image.Frames[0].GetFirstPixel());
Assert.Equal(96, image.Frames[0].PixelWidth);
Assert.Equal(96, image.Frames[0].PixelHeight);
});
}
[Fact]
public void GetDestinationPath_uniquifies_output_filename()
{
File.WriteAllBytes(Path.Combine(_directory, "Test (Test).png"), new byte[0]);
var operation = new ResizeOperation("Test.png", _directory, Settings());
operation.Execute();
Assert.Contains("Test (Test) (1).png", _directory.FileNames);
}
[Fact]
public void GetDestinationPath_uniquifies_output_filename_again()
{
File.WriteAllBytes(Path.Combine(_directory, "Test (Test).png"), new byte[0]);
File.WriteAllBytes(Path.Combine(_directory, "Test (Test) (1).png"), new byte[0]);
var operation = new ResizeOperation("Test.png", _directory, Settings());
operation.Execute();
Assert.Contains("Test (Test) (2).png", _directory.FileNames);
}
[Fact]
public void GetDestinationPath_uses_fileName_format()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(s => s.FileName = "%1_%2_%3_%4_%5_%6"));
operation.Execute();
Assert.Contains("Test_Test_96_96_96_48.png", _directory.FileNames);
}
[Fact]
public void Execute_handles_directories_in_fileName_format()
{
var operation = new ResizeOperation(
"Test.png",
_directory,
Settings(s => s.FileName = @"Directory\%1 (%2)"));
operation.Execute();
Assert.True(File.Exists(_directory + @"\Directory\Test (Test).png"));
}
public void Dispose()
=> _directory.Dispose();
private Settings Settings(Action<Settings> action = null)
{
var settings = new Settings
{
Sizes = new ObservableCollection<ResizeSize>
{
new ResizeSize
{
Name = "Test",
Width = 96,
Height = 96,
},
},
SelectedSizeIndex = 0,
};
action?.Invoke(settings);
return settings;
}
}
}

View File

@@ -0,0 +1,272 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using System.Collections.Generic;
using System.ComponentModel;
using ImageResizer.Properties;
using ImageResizer.Test;
using Xunit;
using Xunit.Extensions;
namespace ImageResizer.Models
{
public class ResizeSizeTests
{
[Fact]
public void Name_works()
{
var size = new ResizeSize();
var e = AssertEx.Raises<PropertyChangedEventArgs>(
h => size.PropertyChanged += h,
h => size.PropertyChanged -= h,
() => size.Name = "Test");
Assert.Equal("Test", size.Name);
Assert.Equal(nameof(ResizeSize.Name), e.Arguments.PropertyName);
}
[Fact]
public void Name_replaces_tokens()
{
var args = new List<(string, string)>
{
("$small$", Resources.Small),
("$medium$", Resources.Medium),
("$large$", Resources.Large),
("$phone$", Resources.Phone),
};
foreach (var (name, expected) in args)
{
var size = new ResizeSize();
size.Name = name;
Assert.Equal(expected, size.Name);
}
}
[Fact]
public void Fit_works()
{
var size = new ResizeSize();
var e = AssertEx.Raises<PropertyChangedEventArgs>(
h => size.PropertyChanged += h,
h => size.PropertyChanged -= h,
() => size.Fit = ResizeFit.Stretch);
Assert.Equal(ResizeFit.Stretch, size.Fit);
Assert.Equal(nameof(ResizeSize.Fit), e.Arguments.PropertyName);
}
[Fact]
public void Width_works()
{
var size = new ResizeSize();
var e = AssertEx.Raises<PropertyChangedEventArgs>(
h => size.PropertyChanged += h,
h => size.PropertyChanged -= h,
() => size.Width = 42);
Assert.Equal(42, size.Width);
Assert.Equal(nameof(ResizeSize.Width), e.Arguments.PropertyName);
}
[Fact]
public void Height_works()
{
var size = new ResizeSize();
var e = AssertEx.Raises<PropertyChangedEventArgs>(
h => size.PropertyChanged += h,
h => size.PropertyChanged -= h,
() => size.Height = 42);
Assert.Equal(42, size.Height);
Assert.Equal(nameof(ResizeSize.Height), e.Arguments.PropertyName);
}
[Fact]
public void HasAuto_returns_true_when_Width_unset()
{
var size = new ResizeSize
{
Width = 0,
Height = 42,
};
Assert.True(size.HasAuto);
}
[Fact]
public void HasAuto_returns_true_when_Height_unset()
{
var size = new ResizeSize
{
Width = 42,
Height = 0,
};
Assert.True(size.HasAuto);
}
[Fact]
public void HasAuto_returns_false_when_Width_and_Height_set()
{
var size = new ResizeSize
{
Width = 42,
Height = 42,
};
Assert.False(size.HasAuto);
}
[Fact]
public void Unit_works()
{
var size = new ResizeSize();
var e = AssertEx.Raises<PropertyChangedEventArgs>(
h => size.PropertyChanged += h,
h => size.PropertyChanged -= h,
() => size.Unit = ResizeUnit.Inch);
Assert.Equal(ResizeUnit.Inch, size.Unit);
Assert.Equal(nameof(ResizeSize.Unit), e.Arguments.PropertyName);
}
[Fact]
public void GetPixelWidth_works()
{
var size = new ResizeSize
{
Width = 1,
Unit = ResizeUnit.Inch,
};
var result = size.GetPixelWidth(100, 96);
Assert.Equal(96, result);
}
[Fact]
public void GetPixelHeight_works()
{
var size = new ResizeSize
{
Height = 1,
Unit = ResizeUnit.Inch,
};
var result = size.GetPixelHeight(100, 96);
Assert.Equal(96, result);
}
[Theory]
[InlineData(ResizeFit.Fit)]
[InlineData(ResizeFit.Fill)]
public void GetPixelHeight_uses_Width_when_scale_by_percent(ResizeFit fit)
{
var size = new ResizeSize
{
Fit = fit,
Width = 100,
Height = 50,
Unit = ResizeUnit.Percent,
};
var result = size.GetPixelHeight(100, 96);
Assert.Equal(100, result);
}
[Fact]
public void ConvertToPixels_works_when_auto_and_fit()
{
var size = new ResizeSize
{
Width = 0,
Fit = ResizeFit.Fit,
};
var result = size.GetPixelWidth(100, 96);
Assert.Equal(double.PositiveInfinity, result);
}
[Fact]
public void ConvertToPixels_works_when_auto_and_not_fit()
{
var size = new ResizeSize
{
Width = 0,
Fit = ResizeFit.Fill,
};
var result = size.GetPixelWidth(100, 96);
Assert.Equal(100, result);
}
[Fact]
public void ConvertToPixels_works_when_inches()
{
var size = new ResizeSize
{
Width = 0.5,
Unit = ResizeUnit.Inch,
};
var result = size.GetPixelWidth(100, 96);
Assert.Equal(48, result);
}
[Fact]
public void ConvertToPixels_works_when_centimeters()
{
var size = new ResizeSize
{
Width = 1,
Unit = ResizeUnit.Centimeter,
};
var result = size.GetPixelWidth(100, 96);
Assert.Equal(38, result, 0);
}
[Fact]
public void ConvertToPixels_works_when_percent()
{
var size = new ResizeSize
{
Width = 50,
Unit = ResizeUnit.Percent,
};
var result = size.GetPixelWidth(200, 96);
Assert.Equal(100, result);
}
[Fact]
public void ConvertToPixels_works_when_pixels()
{
var size = new ResizeSize
{
Width = 50,
Unit = ResizeUnit.Pixel,
};
var result = size.GetPixelWidth(100, 96);
Assert.Equal(50, result);
}
}
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1636:FileHeaderCopyrightTextMustMatch", Justification = "File created under PowerToys.")]
namespace ImageResizer.Properties
{
public class AppFixture : IDisposable
{
public AppFixture()
{
// new App() needs to be created since Settings.Reload() uses App.Current to update properties on the UI thread. App() can be created only once otherwise it results in System.InvalidOperationException : Cannot create more than one System.Windows.Application instance in the same AppDomain.
imageResizerApp = new App();
}
public void Dispose()
{
imageResizerApp = null;
}
private App imageResizerApp;
}
}

View File

@@ -0,0 +1,280 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using ImageResizer.Models;
using ImageResizer.Test;
using Xunit;
using Xunit.Abstractions;
using Xunit.Extensions;
namespace ImageResizer.Properties
{
public class SettingsTests : IClassFixture<AppFixture>, IDisposable
{
public SettingsTests()
{
// Change settings.json path to a temp file
Settings.SettingsPath = ".\\test_settings.json";
}
public void Dispose()
{
if (System.IO.File.Exists(Settings.SettingsPath))
{
System.IO.File.Delete(Settings.SettingsPath);
}
}
[Fact]
public void AllSizes_propagates_Sizes_collection_events()
{
var settings = new Settings
{
Sizes = new ObservableCollection<ResizeSize>(),
CustomSize = new CustomSize(),
};
var ncc = (INotifyCollectionChanged)settings.AllSizes;
var result = AssertEx.Raises<NotifyCollectionChangedEventArgs>(
h => ncc.CollectionChanged += h,
h => ncc.CollectionChanged -= h,
() => settings.Sizes.Add(new ResizeSize()));
Assert.Equal(NotifyCollectionChangedAction.Add, result.Arguments.Action);
}
[Fact]
public void AllSizes_propagates_Sizes_property_events()
{
var settings = new Settings
{
Sizes = new ObservableCollection<ResizeSize>(),
CustomSize = new CustomSize(),
};
Assert.PropertyChanged(
(INotifyPropertyChanged)settings.AllSizes,
"Item[]",
() => settings.Sizes.Add(new ResizeSize()));
}
[Fact]
public void AllSizes_contains_Sizes()
{
var settings = new Settings
{
Sizes = new ObservableCollection<ResizeSize> { new ResizeSize() },
CustomSize = new CustomSize(),
};
Assert.Contains(settings.Sizes[0], settings.AllSizes);
}
[Fact]
public void AllSizes_contains_CustomSize()
{
var settings = new Settings
{
Sizes = new ObservableCollection<ResizeSize>(),
CustomSize = new CustomSize(),
};
Assert.Contains(settings.CustomSize, settings.AllSizes);
}
[Fact]
public void AllSizes_handles_property_events_for_CustomSize()
{
var originalCustomSize = new CustomSize();
var settings = new Settings
{
Sizes = new ObservableCollection<ResizeSize>(),
CustomSize = originalCustomSize,
};
var ncc = (INotifyCollectionChanged)settings.AllSizes;
var result = AssertEx.Raises<NotifyCollectionChangedEventArgs>(
h => ncc.CollectionChanged += h,
h => ncc.CollectionChanged -= h,
() => settings.CustomSize = new CustomSize());
Assert.Equal(NotifyCollectionChangedAction.Replace, result.Arguments.Action);
Assert.Equal(1, result.Arguments.NewItems.Count);
Assert.Equal(settings.CustomSize, result.Arguments.NewItems[0]);
Assert.Equal(0, result.Arguments.NewStartingIndex);
Assert.Equal(1, result.Arguments.OldItems.Count);
Assert.Equal(originalCustomSize, result.Arguments.OldItems[0]);
Assert.Equal(0, result.Arguments.OldStartingIndex);
}
[Fact]
public void FileNameFormat_works()
{
var settings = new Settings { FileName = "{T}%1e%2s%3t%4%5%6%7" };
var result = settings.FileNameFormat;
Assert.Equal("{{T}}{0}e{1}s{2}t{3}{4}{5}%7", result);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
public void SelectedSize_returns_CustomSize_when_out_of_range(int index)
{
var settings = new Settings
{
SelectedSizeIndex = index,
Sizes = new ObservableCollection<ResizeSize>(),
CustomSize = new CustomSize(),
};
var result = settings.SelectedSize;
Assert.Same(settings.CustomSize, result);
}
[Fact]
public void SelectedSize_returns_Size_when_in_range()
{
var settings = new Settings
{
SelectedSizeIndex = 0,
Sizes = new ObservableCollection<ResizeSize>
{
new ResizeSize(),
},
};
var result = settings.SelectedSize;
Assert.Same(settings.Sizes[0], result);
}
[Fact]
public void IDataErrorInfo_Error_returns_empty()
{
var settings = new Settings();
var result = ((IDataErrorInfo)settings).Error;
Assert.Empty(result);
}
[Theory]
[InlineData(0)]
[InlineData(101)]
public void IDataErrorInfo_Item_JpegQualityLevel_returns_error_when_out_of_range(int value)
{
var settings = new Settings { JpegQualityLevel = value };
var result = ((IDataErrorInfo)settings)["JpegQualityLevel"];
Assert.Equal(
string.Format(Resources.ValueMustBeBetween, 1, 100),
result);
}
[Theory]
[InlineData(1)]
[InlineData(100)]
public void IDataErrorInfo_Item_JpegQualityLevel_returns_empty_when_in_range(int value)
{
var settings = new Settings { JpegQualityLevel = value };
var result = ((IDataErrorInfo)settings)["JpegQualityLevel"];
Assert.Empty(result);
}
[Fact]
public void IDataErrorInfo_Item_returns_empty_when_not_JpegQualityLevel()
{
var settings = new Settings();
var result = ((IDataErrorInfo)settings)["Unknown"];
Assert.Empty(result);
}
[Fact]
public void Reload_createsFile_when_FileNotFound()
{
// Arrange
var settings = new Settings();
// Assert
Assert.False(System.IO.File.Exists(Settings.SettingsPath));
// Act
settings.Reload();
// Assert
Assert.True(System.IO.File.Exists(Settings.SettingsPath));
}
[Fact]
public void Save_creates_file()
{
// Arrange
var settings = new Settings();
// Assert
Assert.False(System.IO.File.Exists(Settings.SettingsPath));
// Act
settings.Save();
// Assert
Assert.True(System.IO.File.Exists(Settings.SettingsPath));
}
[Fact]
public void Save_json_is_readable_by_Reload()
{
// Arrange
var settings = new Settings();
// Assert
Assert.False(System.IO.File.Exists(Settings.SettingsPath));
// Act
settings.Save();
settings.Reload(); // If the JSON file created by Save() is not readable this function will throw an error
// Assert
Assert.True(System.IO.File.Exists(Settings.SettingsPath));
}
[Fact]
public void Reload_raises_PropertyChanged_()
{
// Arrange
var settings = new Settings();
settings.Save(); // To create the settings file
// Act
var action = new System.Action(settings.Reload);
// Assert
Assert.PropertyChanged(settings, "ShrinkOnly", action);
Assert.PropertyChanged(settings, "Replace", action);
Assert.PropertyChanged(settings, "IgnoreOrientation", action);
Assert.PropertyChanged(settings, "JpegQualityLevel", action);
Assert.PropertyChanged(settings, "PngInterlaceOption", action);
Assert.PropertyChanged(settings, "TiffCompressOption", action);
Assert.PropertyChanged(settings, "FileName", action);
Assert.PropertyChanged(settings, "Sizes", action);
Assert.PropertyChanged(settings, "KeepDateModified", action);
Assert.PropertyChanged(settings, "FallbackEncoder", action);
Assert.PropertyChanged(settings, "CustomSize", action);
Assert.PropertyChanged(settings, "SelectedSizeIndex", action);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

View File

@@ -0,0 +1,87 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Windows.Media.Imaging;
using Xunit;
namespace ImageResizer.Test
{
internal static class AssertEx
{
public static void All<T>(IEnumerable<T> collection, Action<T> action)
{
foreach (var item in collection)
{
action(item);
}
}
public static void Image(string path, Action<BitmapDecoder> action)
{
using (var stream = File.OpenRead(path))
{
var image = BitmapDecoder.Create(
stream,
BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.None);
action(image);
}
}
public static RaisedEvent<NotifyCollectionChangedEventArgs> Raises<T>(
Action<NotifyCollectionChangedEventHandler> attach,
Action<NotifyCollectionChangedEventHandler> detach,
Action testCode)
where T : NotifyCollectionChangedEventArgs
{
RaisedEvent<NotifyCollectionChangedEventArgs> raisedEvent = null;
NotifyCollectionChangedEventHandler handler = (sender, e)
=> raisedEvent = new RaisedEvent<NotifyCollectionChangedEventArgs>(sender, e);
attach(handler);
testCode();
detach(handler);
Assert.NotNull(raisedEvent);
return raisedEvent;
}
public static RaisedEvent<PropertyChangedEventArgs> Raises<T>(
Action<PropertyChangedEventHandler> attach,
Action<PropertyChangedEventHandler> detach,
Action testCode)
where T : PropertyChangedEventArgs
{
RaisedEvent<PropertyChangedEventArgs> raisedEvent = null;
PropertyChangedEventHandler handler = (sender, e)
=> raisedEvent = new RaisedEvent<PropertyChangedEventArgs>(sender, e);
attach(handler);
testCode();
detach(handler);
Assert.NotNull(raisedEvent);
return raisedEvent;
}
public class RaisedEvent<TArgs>
{
public RaisedEvent(object sender, TArgs args)
{
Sender = sender;
Arguments = args;
}
public object Sender { get; }
public TArgs Arguments { get; }
}
}
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace ImageResizer.Test
{
internal static class BitmapSourceExtensions
{
public static Color GetFirstPixel(this BitmapSource source)
{
var pixel = new byte[4];
new FormatConvertedBitmap(
new CroppedBitmap(source, new Int32Rect(0, 0, 1, 1)),
PixelFormats.Bgra32,
destinationPalette: null,
alphaThreshold: 0)
.CopyPixels(pixel, 4, 0);
return Color.FromArgb(pixel[3], pixel[2], pixel[1], pixel[0]);
}
}
}

View File

@@ -0,0 +1,57 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using Xunit;
using IOPath = System.IO.Path;
namespace ImageResizer
{
public class TestDirectory : IDisposable
{
private readonly string _path;
public TestDirectory()
{
_path = IOPath.Combine(
AppDomain.CurrentDomain.BaseDirectory,
IOPath.GetRandomFileName());
Directory.CreateDirectory(_path);
}
private IEnumerable<string> Files
=> Directory.EnumerateFiles(_path);
public IEnumerable<string> FileNames
=> Files.Select(IOPath.GetFileName);
public string File()
=> Assert.Single(Files);
public void Dispose()
{
var stopwatch = Stopwatch.StartNew();
while (stopwatch.ElapsedMilliseconds < 30000)
{
try
{
Directory.Delete(_path, recursive: true);
break;
}
catch
{
Thread.Sleep(150);
}
}
}
public static implicit operator string(TestDirectory directory)
=> directory._path;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

View File

@@ -0,0 +1,46 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using System;
using System.Globalization;
using ImageResizer.Properties;
using Xunit;
using Xunit.Extensions;
namespace ImageResizer.Views
{
public class TimeRemainingConverterTests
{
[Theory]
[InlineData("HourMinute", 1, 1, 0)]
[InlineData("HourMinutes", 1, 2, 0)]
[InlineData("HoursMinute", 2, 1, 0)]
[InlineData("HoursMinutes", 2, 2, 0)]
[InlineData("MinuteSecond", 0, 1, 1)]
[InlineData("MinuteSeconds", 0, 1, 2)]
[InlineData("MinutesSecond", 0, 2, 1)]
[InlineData("MinutesSeconds", 0, 2, 2)]
[InlineData("Second", 0, 0, 1)]
[InlineData("Seconds", 0, 0, 2)]
public void Convert_works(string resource, int hours, int minutes, int seconds)
{
var timeRemaining = new TimeSpan(hours, minutes, seconds);
var converter = new TimeRemainingConverter();
var result = converter.Convert(
timeRemaining,
targetType: null,
parameter: null,
CultureInfo.InvariantCulture);
Assert.Equal(
string.Format(
Resources.ResourceManager.GetString("Progress_TimeRemaining_" + resource),
hours,
minutes,
seconds),
result);
}
}
}