diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md index 7134d93..c99c897 100644 --- a/.claude/rules/testing.md +++ b/.claude/rules/testing.md @@ -18,6 +18,25 @@ 標準に則る.NUnit の慣例(AAA: Arrange-Act-Assert)に従い,テストは実装のなぞり書きではなく**仕様(期待される入出力)を基準**に書く. +## アサーションの書き方 (Assertion Style) + +**制約モデル(`Assert.That` + `Is.*` / `Does.*`)のみを使う**.Classic assertion(`Assert.AreEqual`・`Assert.IsTrue`・`StringAssert.Contains` 等)は新規に書かないこと. + +理由: NUnit 4 で Classic assertion は `Assert` から削除され `NUnit.Framework.Legacy.ClassicAssert` へ移動した.一方で制約モデルは NUnit 3 でも 4 でも同じく動くため,制約モデルに揃えておけば NUnit のメジャー更新にテストコードの変更なしで追従できる(既存の 209 箇所は 2026-08-28 に移行済み). + +| 用途 | 書き方 | +| --- | --- | +| 等値 | `Assert.That(actual, Is.EqualTo(expected))` | +| 浮動小数点の等値 | `Assert.That(actual, Is.EqualTo(expected).Within(delta))` | +| 真偽 | `Assert.That(x, Is.True)` / `Assert.That(x, Is.False)` | +| null | `Assert.That(x, Is.Null)` / `Assert.That(x, Is.Not.Null)` | +| 同一性 | `Assert.That(actual, Is.SameAs(expected))` | +| 部分文字列 | `Assert.That(actual, Does.Contain(expected))` | +| 例外 | `Assert.Throws(...)` / `Assert.DoesNotThrow(...)`(これらは変更不要) | + +- **引数の順序に注意する**.Classic は `(expected, actual)` だが制約モデルは `(actual, 制約)` である.とくに `Does.Contain` は第 1 引数が**検査対象**で,期待する部分文字列は制約の側に入る(逆にすると意味が反転したまま通ってしまう場合がある). +- 浮動小数点の比較で `.Within(...)` を落とさないこと.厳密比較になりフレーキーになる. + ## テストの種類 (Test Types) | 種類 | 対象 | 自動化 | 実行タイミング | @@ -79,10 +98,7 @@ テストプロジェクトは本体に合わせたレガシー形式(packages.config)のため `dotnet test` は使えない.ビルド後に `vstest.console.exe` を **x64** で実行する(ネイティブ DLL を x64 でロードするため). -```powershell -& "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe" TIASshot.sln /t:Build /p:Configuration=Debug /p:Platform=x64 -& "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe" "TIASshot.Tests\bin\x64\Debug\TIASshot.Tests.dll" /Platform:x64 -``` +**具体的なコマンドは [ENV_04_開発コマンド](../../docs/02_ENV/ENV_04_開発コマンド.md) を参照する**(本 rule は方針,ENV_04 はコマンドという役割分担).MSBuild・`vstest.console.exe` の場所は VS のエディション(Community / Professional / Enterprise / Build Tools)によって変わるため,パスを直書きせず ENV_04 の `vswhere` による解決手順を使うこと. Visual Studio 上ではテストエクスプローラーから実行できる(プラットフォームを x64 にすること). diff --git a/TIASshot.Tests/BitmapUtilTests.cs b/TIASshot.Tests/BitmapUtilTests.cs index 05a7041..4a89d1b 100644 --- a/TIASshot.Tests/BitmapUtilTests.cs +++ b/TIASshot.Tests/BitmapUtilTests.cs @@ -33,9 +33,9 @@ public void FastClone_24bppRgb_サイズとPixelFormatが入力と一致する() { using (var src = CreateSolidBitmap(4, 3, PixelFormat.Format24bppRgb, Color.FromArgb(10, 20, 30))) using (var dst = BitmapUtil.FastClone(src)) { - Assert.AreEqual(src.Width, dst.Width, "幅が一致すること"); - Assert.AreEqual(src.Height, dst.Height, "高さが一致すること"); - Assert.AreEqual(src.PixelFormat, dst.PixelFormat, "PixelFormat が一致すること"); + Assert.That(dst.Width, Is.EqualTo(src.Width), "幅が一致すること"); + Assert.That(dst.Height, Is.EqualTo(src.Height), "高さが一致すること"); + Assert.That(dst.PixelFormat, Is.EqualTo(src.PixelFormat), "PixelFormat が一致すること"); } } @@ -57,9 +57,9 @@ public void FastClone_32bppArgb_サイズとPixelFormatが入力と一致する() { using (var src = CreateSolidBitmap(5, 4, PixelFormat.Format32bppArgb, Color.FromArgb(200, 10, 20, 30))) using (var dst = BitmapUtil.FastClone(src)) { - Assert.AreEqual(src.Width, dst.Width, "幅が一致すること"); - Assert.AreEqual(src.Height, dst.Height, "高さが一致すること"); - Assert.AreEqual(src.PixelFormat, dst.PixelFormat, "PixelFormat が一致すること"); + Assert.That(dst.Width, Is.EqualTo(src.Width), "幅が一致すること"); + Assert.That(dst.Height, Is.EqualTo(src.Height), "高さが一致すること"); + Assert.That(dst.PixelFormat, Is.EqualTo(src.PixelFormat), "PixelFormat が一致すること"); } } @@ -88,13 +88,13 @@ src.Dispose(); try { - Assert.AreEqual(4, dst.Width, "src Dispose 後も dst の幅が読めること"); - Assert.AreEqual(4, dst.Height, "src Dispose 後も dst の高さが読めること"); + Assert.That(dst.Width, Is.EqualTo(4), "src Dispose 後も dst の幅が読めること"); + Assert.That(dst.Height, Is.EqualTo(4), "src Dispose 後も dst の高さが読めること"); Color px = dst.GetPixel(0, 0); - Assert.AreEqual(11, px.R, "src Dispose 後も dst の画素(R)が読めること"); - Assert.AreEqual(22, px.G, "src Dispose 後も dst の画素(G)が読めること"); - Assert.AreEqual(33, px.B, "src Dispose 後も dst の画素(B)が読めること"); + Assert.That(px.R, Is.EqualTo(11), "src Dispose 後も dst の画素(R)が読めること"); + Assert.That(px.G, Is.EqualTo(22), "src Dispose 後も dst の画素(G)が読めること"); + Assert.That(px.B, Is.EqualTo(33), "src Dispose 後も dst の画素(B)が読めること"); } finally { dst.Dispose(); } @@ -110,9 +110,9 @@ dst.SetPixel(0, 0, Color.FromArgb(0, 0, 0)); Color srcPx = src.GetPixel(0, 0); - Assert.AreEqual(50, srcPx.R, "dst 変更後も src の R は不変"); - Assert.AreEqual(60, srcPx.G, "dst 変更後も src の G は不変"); - Assert.AreEqual(70, srcPx.B, "dst 変更後も src の B は不変"); + Assert.That(srcPx.R, Is.EqualTo(50), "dst 変更後も src の R は不変"); + Assert.That(srcPx.G, Is.EqualTo(60), "dst 変更後も src の G は不変"); + Assert.That(srcPx.B, Is.EqualTo(70), "dst 変更後も src の B は不変"); } } @@ -131,14 +131,14 @@ Color beforeCorner = src.GetPixel(src.Width - 1, src.Height - 1); using (var dst = BitmapUtil.FastClone(src)) { - Assert.IsNotNull(dst); + Assert.That(dst, Is.Not.Null); } Color after00 = src.GetPixel(0, 0); Color afterCorner = src.GetPixel(src.Width - 1, src.Height - 1); - Assert.AreEqual(before00, after00, "FastClone 呼び出し前後で (0,0) の画素が不変であること"); - Assert.AreEqual(beforeCorner, afterCorner, "FastClone 呼び出し前後で末尾画素が不変であること"); + Assert.That(after00, Is.EqualTo(before00), "FastClone 呼び出し前後で (0,0) の画素が不変であること"); + Assert.That(afterCorner, Is.EqualTo(beforeCorner), "FastClone 呼び出し前後で末尾画素が不変であること"); } } @@ -165,8 +165,8 @@ public void FastClone_幅が4の倍数でない24bppRgb_サイズが一致する() { using (var src = CreateGradientBitmap(5, 3, PixelFormat.Format24bppRgb)) using (var dst = BitmapUtil.FastClone(src)) { - Assert.AreEqual(5, dst.Width); - Assert.AreEqual(3, dst.Height); + Assert.That(dst.Width, Is.EqualTo(5)); + Assert.That(dst.Height, Is.EqualTo(3)); } } @@ -206,15 +206,15 @@ "8bppIndexed を渡しても例外をスローしないこと"); try { - Assert.IsNotNull(dst, "8bppIndexed のフォールバックコピーは null であってはならない"); - Assert.AreNotSame(src, dst, "入力とは別インスタンスであること"); - Assert.AreEqual(src.Width, dst.Width, "幅が一致すること"); - Assert.AreEqual(src.Height, dst.Height, "高さが一致すること"); + Assert.That(dst, Is.Not.Null, "8bppIndexed のフォールバックコピーは null であってはならない"); + Assert.That(dst, Is.Not.SameAs(src), "入力とは別インスタンスであること"); + Assert.That(dst.Width, Is.EqualTo(src.Width), "幅が一致すること"); + Assert.That(dst.Height, Is.EqualTo(src.Height), "高さが一致すること"); // 解決済みの色(パレット適用後の ARGB)が画素ごとに一致すること - Assert.AreEqual(src.GetPixel(0, 0), dst.GetPixel(0, 0), "(0,0) の色が一致すること"); - Assert.AreEqual(src.GetPixel(1, 1), dst.GetPixel(1, 1), "(1,1) の色が一致すること"); - Assert.AreEqual(src.GetPixel(3, 3), dst.GetPixel(3, 3), "(3,3) の色が一致すること"); + Assert.That(dst.GetPixel(0, 0), Is.EqualTo(src.GetPixel(0, 0)), "(0,0) の色が一致すること"); + Assert.That(dst.GetPixel(1, 1), Is.EqualTo(src.GetPixel(1, 1)), "(1,1) の色が一致すること"); + Assert.That(dst.GetPixel(3, 3), Is.EqualTo(src.GetPixel(3, 3)), "(3,3) の色が一致すること"); // 独立性: src を Dispose 後も dst の画素が読めること } finally { @@ -242,7 +242,7 @@ try { Color actual = dst.GetPixel(0, 0); - Assert.AreEqual(expected, actual, "src Dispose 後も dst の色が読めること"); + Assert.That(actual, Is.EqualTo(expected), "src Dispose 後も dst の色が読めること"); } finally { dst.Dispose(); } @@ -258,7 +258,7 @@ [Test] public void FastClone_null入力_nullを返す() { Bitmap result = BitmapUtil.FastClone(null); - Assert.IsNull(result, "null 入力に対して null を返すこと(例外をスローしない)"); + Assert.That(result, Is.Null, "null 入力に対して null を返すこと(例外をスローしない)"); } // --------------------------------------------------------------- @@ -314,9 +314,9 @@ /// LockBits で生バイトを取得し,行ごとに有効バイト幅(パディング除外)だけを比較する。 /// private static void AssertPixelsEqual(Bitmap expected, Bitmap actual) { - Assert.AreEqual(expected.Width, actual.Width, "幅が一致すること(画素比較の前提)"); - Assert.AreEqual(expected.Height, actual.Height, "高さが一致すること(画素比較の前提)"); - Assert.AreEqual(expected.PixelFormat, actual.PixelFormat, "PixelFormat が一致すること(画素比較の前提)"); + Assert.That(actual.Width, Is.EqualTo(expected.Width), "幅が一致すること(画素比較の前提)"); + Assert.That(actual.Height, Is.EqualTo(expected.Height), "高さが一致すること(画素比較の前提)"); + Assert.That(actual.PixelFormat, Is.EqualTo(expected.PixelFormat), "PixelFormat が一致すること(画素比較の前提)"); var rect = new Rectangle(0, 0, expected.Width, expected.Height); BitmapData expData = expected.LockBits(rect, ImageLockMode.ReadOnly, expected.PixelFormat); @@ -335,7 +335,7 @@ IntPtr.Add(actData.Scan0, y * actData.Stride), actRow, 0, validBytesPerRow); for (int i = 0; i < validBytesPerRow; i++) { - Assert.AreEqual(expRow[i], actRow[i], + Assert.That(actRow[i], Is.EqualTo(expRow[i]), $"行 y={y} のバイト位置 {i}(パディング除外後)が一致すること"); } } diff --git a/TIASshot.Tests/ColorCorrectorTests.cs b/TIASshot.Tests/ColorCorrectorTests.cs index b06447b..bc1594f 100644 --- a/TIASshot.Tests/ColorCorrectorTests.cs +++ b/TIASshot.Tests/ColorCorrectorTests.cs @@ -31,8 +31,8 @@ // Act using (var dst = corrector.ExtendMat(src, channels: 4)) { // Assert - Assert.AreEqual(2, dst.Rows, "行数は変わらない"); - Assert.AreEqual(4, dst.Cols, "列数は指定した channels 数になる"); + Assert.That(dst.Rows, Is.EqualTo(2), "行数は変わらない"); + Assert.That(dst.Cols, Is.EqualTo(4), "列数は指定した channels 数になる"); } } } @@ -54,7 +54,7 @@ using (var dst = corrector.ExtendMat(src, channels: 4)) { // Assert: 列 0 は全行で 1.0 for (int row = 0; row < dst.Rows; row++) { - Assert.AreEqual(1.0, dst.At(row, 0), 1e-10, + Assert.That(dst.At(row, 0), Is.EqualTo(1.0).Within(1e-10), $"row={row}: 列0(定数項)は 1.0 であること"); } } @@ -76,11 +76,11 @@ using (var dst = corrector.ExtendMat(src, channels: 4)) { // Assert // ExtendChannels[1]={0,3,3}: vals[0]*vals[3]*vals[3] = R*1*1 = 30 - Assert.AreEqual(30.0, dst.At(0, 1), 1e-10, "列1 は R"); + Assert.That(dst.At(0, 1), Is.EqualTo(30.0).Within(1e-10), "列1 は R"); // ExtendChannels[2]={1,3,3}: vals[1]*vals[3]*vals[3] = G*1*1 = 20 - Assert.AreEqual(20.0, dst.At(0, 2), 1e-10, "列2 は G"); + Assert.That(dst.At(0, 2), Is.EqualTo(20.0).Within(1e-10), "列2 は G"); // ExtendChannels[3]={2,3,3}: vals[2]*vals[3]*vals[3] = B*1*1 = 10 - Assert.AreEqual(10.0, dst.At(0, 3), 1e-10, "列3 は B"); + Assert.That(dst.At(0, 3), Is.EqualTo(10.0).Within(1e-10), "列3 は B"); } } } @@ -99,7 +99,7 @@ // Act using (var dst = corrector.ExtendMat(src, channels: 5)) { // Assert: 列4(i=4)= R*G = 30*20 = 600 - Assert.AreEqual(600.0, dst.At(0, 4), 1e-10, "列4 は R*G = 30*20 = 600"); + Assert.That(dst.At(0, 4), Is.EqualTo(600.0).Within(1e-10), "列4 は R*G = 30*20 = 600"); } } } @@ -117,7 +117,7 @@ var dst = corrector.ExtendMat(src, channels: 4); // Assert: 列数が変わらない(src のまま返る) - Assert.AreEqual(5, dst.Cols, "3列でない入力はそのまま返す"); + Assert.That(dst.Cols, Is.EqualTo(5), "3列でない入力はそのまま返す"); // dst == src の参照なので Dispose しない(src の using で解放される) } } @@ -139,8 +139,8 @@ // Act using (var conv = corrector.CalcConvertMatrix(src, target, channels: 4)) { // Assert: 変換行列は channels x 3 = 4 x 3 - Assert.AreEqual(4, conv.Rows, "行数(channels)は 4 であること"); - Assert.AreEqual(3, conv.Cols, "列数は 3(RGB チャネル)であること"); + Assert.That(conv.Rows, Is.EqualTo(4), "行数(channels)は 4 であること"); + Assert.That(conv.Cols, Is.EqualTo(3), "列数は 3(RGB チャネル)であること"); } } } @@ -158,8 +158,8 @@ // Act using (var conv = corrector.CalcConvertMatrix(src, target, channels: 6)) { // Assert - Assert.AreEqual(6, conv.Rows, "行数(channels)は 6 であること"); - Assert.AreEqual(3, conv.Cols, "列数は 3(RGB チャネル)であること"); + Assert.That(conv.Rows, Is.EqualTo(6), "行数(channels)は 6 であること"); + Assert.That(conv.Cols, Is.EqualTo(3), "列数は 3(RGB チャネル)であること"); } } } @@ -187,11 +187,11 @@ // 行0(定数項)=0, 行1(R)=[1,0,0], 行2(G)=[0,1,0], 行3(B)=[0,0,1] using (var dst = corrector.ConvertColor(src, conv)) { // Assert: 出力は 1x3, 値は B=10, G=20, R=30 - Assert.AreEqual(1, dst.Rows, "出力行数は入力と同じ"); - Assert.AreEqual(3, dst.Cols, "出力列数は 3(RGB)"); - Assert.AreEqual(10.0, dst.At(0, 0), 1e-10, "出力 B = 10"); - Assert.AreEqual(20.0, dst.At(0, 1), 1e-10, "出力 G = 20"); - Assert.AreEqual(30.0, dst.At(0, 2), 1e-10, "出力 R = 30"); + Assert.That(dst.Rows, Is.EqualTo(1), "出力行数は入力と同じ"); + Assert.That(dst.Cols, Is.EqualTo(3), "出力列数は 3(RGB)"); + Assert.That(dst.At(0, 0), Is.EqualTo(10.0).Within(1e-10), "出力 B = 10"); + Assert.That(dst.At(0, 1), Is.EqualTo(20.0).Within(1e-10), "出力 G = 20"); + Assert.That(dst.At(0, 2), Is.EqualTo(30.0).Within(1e-10), "出力 R = 30"); } } } @@ -220,8 +220,8 @@ // Act using (var dst = corrector.ConvertColor(src, conv)) { // Assert: 出力は 5行 3列 - Assert.AreEqual(5, dst.Rows, "出力行数は入力行数と同じ"); - Assert.AreEqual(3, dst.Cols, "出力列数は 3(RGB)"); + Assert.That(dst.Rows, Is.EqualTo(5), "出力行数は入力行数と同じ"); + Assert.That(dst.Cols, Is.EqualTo(3), "出力列数は 3(RGB)"); } } } @@ -308,9 +308,9 @@ // Act using (var dst = corrector.ConvertImage(src, conv)) { // Assert: 型・サイズ - Assert.AreEqual(MatType.CV_8UC3, dst.Type(), "出力型は CV_8UC3"); - Assert.AreEqual(2, dst.Rows, "出力行数は入力と同じ"); - Assert.AreEqual(2, dst.Cols, "出力列数は入力と同じ"); + Assert.That(dst.Type(), Is.EqualTo(MatType.CV_8UC3), "出力型は CV_8UC3"); + Assert.That(dst.Rows, Is.EqualTo(2), "出力行数は入力と同じ"); + Assert.That(dst.Cols, Is.EqualTo(2), "出力列数は入力と同じ"); } } } @@ -335,9 +335,9 @@ using (var dst = corrector.ConvertImage(src, conv)) { // Assert: 出力ピクセルが入力と同一値 var pixel = dst.At(0, 0); - Assert.AreEqual(50, pixel.Item0, "出力 B = 50"); - Assert.AreEqual(100, pixel.Item1, "出力 G = 100"); - Assert.AreEqual(150, pixel.Item2, "出力 R = 150"); + Assert.That(pixel.Item0, Is.EqualTo(50), "出力 B = 50"); + Assert.That(pixel.Item1, Is.EqualTo(100), "出力 G = 100"); + Assert.That(pixel.Item2, Is.EqualTo(150), "出力 R = 150"); } } } @@ -359,9 +359,9 @@ for (int row = 0; row < dst.Rows; row++) { for (int col = 0; col < dst.Cols; col++) { var pixel = dst.At(row, col); - Assert.AreEqual(0, pixel.Item0, $"row={row}, col={col}: B は 0"); - Assert.AreEqual(0, pixel.Item1, $"row={row}, col={col}: G は 0"); - Assert.AreEqual(0, pixel.Item2, $"row={row}, col={col}: R は 0"); + Assert.That(pixel.Item0, Is.EqualTo(0), $"row={row}, col={col}: B は 0"); + Assert.That(pixel.Item1, Is.EqualTo(0), $"row={row}, col={col}: G は 0"); + Assert.That(pixel.Item2, Is.EqualTo(0), $"row={row}, col={col}: R は 0"); } } } @@ -390,11 +390,11 @@ // Assert: 出力が正しいこと(解放済み Mat からの読み出しでないことの確認) using (dst) { - Assert.AreEqual(MatType.CV_8UC3, dst.Type(), $"呼び出し {call + 1} 回目: 型は CV_8UC3"); + Assert.That(dst.Type(), Is.EqualTo(MatType.CV_8UC3), $"呼び出し {call + 1} 回目: 型は CV_8UC3"); var pixel = dst.At(0, 0); - Assert.AreEqual(50, pixel.Item0, $"呼び出し {call + 1} 回目: B = 50"); - Assert.AreEqual(100, pixel.Item1, $"呼び出し {call + 1} 回目: G = 100"); - Assert.AreEqual(150, pixel.Item2, $"呼び出し {call + 1} 回目: R = 150"); + Assert.That(pixel.Item0, Is.EqualTo(50), $"呼び出し {call + 1} 回目: B = 50"); + Assert.That(pixel.Item1, Is.EqualTo(100), $"呼び出し {call + 1} 回目: G = 100"); + Assert.That(pixel.Item2, Is.EqualTo(150), $"呼び出し {call + 1} 回目: R = 150"); } } } @@ -413,12 +413,12 @@ using (var conv = CreateIdentityLikeConvMat()) { var corrector = MakeCorrectorWith4Channels(); - Assert.AreEqual(MatType.CV_8UC3, src.Type(), "呼び出し前は CV_8UC3"); + Assert.That(src.Type(), Is.EqualTo(MatType.CV_8UC3), "呼び出し前は CV_8UC3"); // Act using (var dst = corrector.ConvertImage(src, conv)) { // Assert: 1 回目の呼び出し後、src は CV_64FC3 に変化している(in-place 書き換えの既知挙動) - Assert.AreEqual(MatType.CV_64FC3, src.Type(), + Assert.That(src.Type(), Is.EqualTo(MatType.CV_64FC3), "ConvertImage 呼び出し後、src は in-place で CV_64FC3 に変換される(優先度4 の既知挙動)"); } } @@ -452,25 +452,25 @@ foreach (var kv in firstSaved) { var name = Path.GetFileName(kv.Key); if (name.Contains("convrgb2xyz") || name.Contains("tccsrgb") || name.Contains("convsrgb2xyz")) { - Assert.IsTrue(kv.Value.IsDisposed, $"中間 Mat は解放済みのはず: {name}"); + Assert.That(kv.Value.IsDisposed, Is.True, $"中間 Mat は解放済みのはず: {name}"); } } // 入力 tccRgb は ColorCorrector に破棄されない(所有権は呼び出し側) var tccRgbSaved = firstSaved.First(kv => Path.GetFileName(kv.Key).Contains("tccrgb")).Value; - Assert.IsFalse(tccRgbSaved.IsDisposed, "入力 tccRgb は破棄されない(所有権は呼び出し側)"); - Assert.IsFalse(tccRgb.IsDisposed, "入力 tccRgb 本体も生存している"); + Assert.That(tccRgbSaved.IsDisposed, Is.False, "入力 tccRgb は破棄されない(所有権は呼び出し側)"); + Assert.That(tccRgb.IsDisposed, Is.False, "入力 tccRgb 本体も生存している"); // 保持される変換行列(ConvRgb2Srgb, ch4)は 1 回目校正後に生存 var keptCh4 = firstSaved.First(kv => { var n = Path.GetFileName(kv.Key); return n.Contains("convrgb2srgb") && n.Contains("04"); }).Value; - Assert.IsFalse(keptCh4.IsDisposed, "保持中の変換行列は 1 回目校正後に生存している"); + Assert.That(keptCh4.IsDisposed, Is.False, "保持中の変換行列は 1 回目校正後に生存している"); // 2回目の校正:旧エントリ(1回目の保持行列)が破棄される corrector.CalcTcc(tccRgb, "dummy", (path, mat) => { }); - Assert.IsTrue(keptCh4.IsDisposed, "再校正で古い変換行列(旧エントリ)が破棄される"); + Assert.That(keptCh4.IsDisposed, Is.True, "再校正で古い変換行列(旧エントリ)が破棄される"); } } @@ -508,11 +508,11 @@ // Act using (var conv = corrector.CalcConvertMatrix(src, target, channels: 4)) { // Assert - Assert.AreEqual(1, corrector.CapturedExtended.Count, "ExtendMat は 1 回呼ばれる"); + Assert.That(corrector.CapturedExtended.Count, Is.EqualTo(1), "ExtendMat は 1 回呼ばれる"); var extended = corrector.CapturedExtended[0]; - Assert.AreNotSame(src, extended, "通常入力では新規 Mat が確保される(前提確認)"); - Assert.IsTrue(extended.IsDisposed, "中間拡張 Mat は CalcConvertMatrix 完了時に解放される"); - Assert.IsFalse(src.IsDisposed, "入力 src は解放されない(所有権は呼び出し側)"); + Assert.That(extended, Is.Not.SameAs(src), "通常入力では新規 Mat が確保される(前提確認)"); + Assert.That(extended.IsDisposed, Is.True, "中間拡張 Mat は CalcConvertMatrix 完了時に解放される"); + Assert.That(src.IsDisposed, Is.False, "入力 src は解放されない(所有権は呼び出し側)"); } } } @@ -532,11 +532,11 @@ // Act using (var dst = corrector.ConvertColor(src, conv)) { // Assert - Assert.AreEqual(1, corrector.CapturedExtended.Count, "ExtendMat は 1 回呼ばれる"); + Assert.That(corrector.CapturedExtended.Count, Is.EqualTo(1), "ExtendMat は 1 回呼ばれる"); var extended = corrector.CapturedExtended[0]; - Assert.AreNotSame(src, extended, "通常入力では新規 Mat が確保される(前提確認)"); - Assert.IsTrue(extended.IsDisposed, "中間拡張 Mat は ConvertColor 完了時に解放される"); - Assert.IsFalse(src.IsDisposed, "入力 src は解放されない(所有権は呼び出し側)"); + Assert.That(extended, Is.Not.SameAs(src), "通常入力では新規 Mat が確保される(前提確認)"); + Assert.That(extended.IsDisposed, Is.True, "中間拡張 Mat は ConvertColor 完了時に解放される"); + Assert.That(src.IsDisposed, Is.False, "入力 src は解放されない(所有権は呼び出し側)"); } } } @@ -560,8 +560,8 @@ // Act using (var conv = corrector.CalcConvertMatrix(src, target, channels: 4)) { // Assert - Assert.AreSame(src, corrector.CapturedExtended[0], "パススルー入力では src がそのまま返る(前提確認)"); - Assert.IsFalse(src.IsDisposed, "パススルー入力の src は解放されない(所有権は呼び出し側)"); + Assert.That(corrector.CapturedExtended[0], Is.SameAs(src), "パススルー入力では src がそのまま返る(前提確認)"); + Assert.That(src.IsDisposed, Is.False, "パススルー入力の src は解放されない(所有権は呼び出し側)"); } } } @@ -580,8 +580,8 @@ // Act using (var dst = corrector.ConvertColor(src, conv)) { // Assert - Assert.AreSame(src, corrector.CapturedExtended[0], "パススルー入力では src がそのまま返る(前提確認)"); - Assert.IsFalse(src.IsDisposed, "パススルー入力の src は解放されない(所有権は呼び出し側)"); + Assert.That(corrector.CapturedExtended[0], Is.SameAs(src), "パススルー入力では src がそのまま返る(前提確認)"); + Assert.That(src.IsDisposed, Is.False, "パススルー入力の src は解放されない(所有権は呼び出し側)"); } } } diff --git a/TIASshot.Tests/ConfigTests.cs b/TIASshot.Tests/ConfigTests.cs index 6d6b36b..8dd14ee 100644 --- a/TIASshot.Tests/ConfigTests.cs +++ b/TIASshot.Tests/ConfigTests.cs @@ -52,7 +52,7 @@ [Test] public void GetFloat_存在するキー_正しい値を返す() { var value = Config.GetFloat("FloatVal"); - Assert.AreEqual(ExpectedFloat, value, 1e-6f); + Assert.That(value, Is.EqualTo(ExpectedFloat).Within(1e-6f)); } /// @@ -61,7 +61,7 @@ [Test] public void GetInt_存在するキー_正しい値を返す() { var value = Config.GetInt("IntVal"); - Assert.AreEqual(ExpectedInt, value); + Assert.That(value, Is.EqualTo(ExpectedInt)); } /// @@ -70,7 +70,7 @@ [Test] public void GetString_存在するキー_正しい値を返す() { var value = Config.GetString("StrVal"); - Assert.AreEqual(ExpectedString, value); + Assert.That(value, Is.EqualTo(ExpectedString)); } /// @@ -103,7 +103,7 @@ [Test] public void GetString_ネスト要素_正しい値を返す() { var value = Config.GetString("Nested/Child"); - Assert.AreEqual(ExpectedNested, value); + Assert.That(value, Is.EqualTo(ExpectedNested)); } /// @@ -142,7 +142,7 @@ System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-DE"); var value = Config.GetFloat("FloatVal"); - Assert.AreEqual(ExpectedFloat, value, 1e-6f); + Assert.That(value, Is.EqualTo(ExpectedFloat).Within(1e-6f)); } finally { System.Threading.Thread.CurrentThread.CurrentCulture = original; } @@ -157,7 +157,7 @@ var repoConfigPath = Path.GetFullPath(Path.Combine( TestContext.CurrentContext.TestDirectory, "..", "..", "..", "..", "TIASshot", "config.xml")); - Assert.IsTrue(File.Exists(repoConfigPath), $"同梱 config.xml が見つからない: {repoConfigPath}"); + Assert.That(File.Exists(repoConfigPath), Is.True, $"同梱 config.xml が見つからない: {repoConfigPath}"); Config.Load(repoConfigPath); string[] intKeys = { @@ -178,8 +178,8 @@ Assert.DoesNotThrow(() => Config.GetFloat(key), $"GetFloat(\"{key}\") が例外を投げた"); } // ゼロ除算・校正停止に直結する値が有効値で読めることを固定する - Assert.AreNotEqual(0, Config.GetInt("Calib/UpdateInterval")); - Assert.AreNotEqual(0.0f, Config.GetFloat("Calib/UpdateRate")); + Assert.That(Config.GetInt("Calib/UpdateInterval"), Is.Not.EqualTo(0)); + Assert.That(Config.GetFloat("Calib/UpdateRate"), Is.Not.EqualTo(0.0f)); } } } diff --git a/TIASshot.Tests/GainCalcCalcGainValueTests.cs b/TIASshot.Tests/GainCalcCalcGainValueTests.cs index 56e92d3..2a331ca 100644 --- a/TIASshot.Tests/GainCalcCalcGainValueTests.cs +++ b/TIASshot.Tests/GainCalcCalcGainValueTests.cs @@ -20,7 +20,7 @@ [Test] public void CalcGainValue_比率が範囲内_従来どおり四捨五入した値を返す() { int result = GainCalc.CalcGainValue(100, 1.5f, 0, 255); - Assert.AreEqual(150, result); + Assert.That(result, Is.EqualTo(150)); } /// @@ -30,7 +30,7 @@ [Test] public void CalcGainValue_小数部が切り上がる場合_四捨五入した値を返す() { int result = GainCalc.CalcGainValue(100, 1.006f, 0, 255); - Assert.AreEqual(101, result); + Assert.That(result, Is.EqualTo(101)); } /// @@ -40,7 +40,7 @@ [Test] public void CalcGainValue_比率が1_現在値をそのまま返す() { int result = GainCalc.CalcGainValue(133, 1.0f, 0, 255); - Assert.AreEqual(133, result); + Assert.That(result, Is.EqualTo(133)); } // --------------------------------------------------------------- @@ -55,7 +55,7 @@ [Test] public void CalcGainValue_結果がrangeMaxを超える_rangeMaxを返す() { int result = GainCalc.CalcGainValue(133, 2.008f, 0, 255); - Assert.AreEqual(255, result); + Assert.That(result, Is.EqualTo(255)); } /// @@ -65,7 +65,7 @@ [Test] public void CalcGainValue_結果がrangeMin未満_rangeMinを返す() { int result = GainCalc.CalcGainValue(10, 0.01f, 8, 255); - Assert.AreEqual(8, result); + Assert.That(result, Is.EqualTo(8)); } /// @@ -75,7 +75,7 @@ [Test] public void CalcGainValue_比率が負_rangeMinを返す() { int result = GainCalc.CalcGainValue(100, -3.0f, 0, 255); - Assert.AreEqual(0, result); + Assert.That(result, Is.EqualTo(0)); } // --------------------------------------------------------------- @@ -92,7 +92,7 @@ [Test] public void CalcGainValue_比率がInfinity_rangeMaxを返す() { int result = GainCalc.CalcGainValue(133, float.PositiveInfinity, 0, 255); - Assert.AreEqual(255, result); + Assert.That(result, Is.EqualTo(255)); } /// @@ -101,7 +101,7 @@ [Test] public void CalcGainValue_比率が負のInfinity_rangeMinを返す() { int result = GainCalc.CalcGainValue(133, float.NegativeInfinity, 0, 255); - Assert.AreEqual(0, result); + Assert.That(result, Is.EqualTo(0)); } /// @@ -112,7 +112,7 @@ [Test] public void CalcGainValue_比率がNaN_現在値を維持する() { int result = GainCalc.CalcGainValue(133, float.NaN, 0, 255); - Assert.AreEqual(133, result); + Assert.That(result, Is.EqualTo(133)); } // --------------------------------------------------------------- diff --git a/TIASshot.Tests/GainCalcTests.cs b/TIASshot.Tests/GainCalcTests.cs index 121ecaf..f1ea45f 100644 --- a/TIASshot.Tests/GainCalcTests.cs +++ b/TIASshot.Tests/GainCalcTests.cs @@ -18,7 +18,7 @@ [Test] public void CalcRatio_通常ケースupdateRate0_5_正しい比率を返す() { float result = GainCalc.CalcRatio(100.0f, 200.0f, 0.5f); - Assert.AreEqual(1.5f, result, 1e-6f); + Assert.That(result, Is.EqualTo(1.5f).Within(1e-6f)); } // --------------------------------------------------------------- @@ -32,7 +32,7 @@ [Test] public void CalcRatio_updateRate1_0_係数1倍の比率を返す() { float result = GainCalc.CalcRatio(100.0f, 200.0f, 1.0f); - Assert.AreEqual(2.0f, result, 1e-6f); + Assert.That(result, Is.EqualTo(2.0f).Within(1e-6f)); } /// @@ -42,7 +42,7 @@ [Test] public void CalcRatio_updateRate0_1_updateRateが小さいほど変化量が小さい() { float result = GainCalc.CalcRatio(100.0f, 200.0f, 0.1f); - Assert.AreEqual(1.1f, result, 1e-6f); + Assert.That(result, Is.EqualTo(1.1f).Within(1e-6f)); } // --------------------------------------------------------------- @@ -56,7 +56,7 @@ [Test] public void CalcRatio_valueがtargetと等しい_updateRate0_5_比率は1() { float result = GainCalc.CalcRatio(150.0f, 150.0f, 0.5f); - Assert.AreEqual(1.0f, result, 1e-6f); + Assert.That(result, Is.EqualTo(1.0f).Within(1e-6f)); } /// @@ -68,7 +68,7 @@ public void CalcRatio_valueがtargetと等しい_updateRateを変えても結果が同じ() { float result05 = GainCalc.CalcRatio(150.0f, 150.0f, 0.5f); float result10 = GainCalc.CalcRatio(150.0f, 150.0f, 1.0f); - Assert.AreEqual(result05, result10, 1e-6f, "value==target のとき updateRate によらず結果が同じ"); + Assert.That(result10, Is.EqualTo(result05).Within(1e-6f), "value==target のとき updateRate によらず結果が同じ"); } // --------------------------------------------------------------- @@ -84,7 +84,7 @@ public void CalcRatio_value255_updateRate0_5_係数は常に1_0になる() { float expected = 200.0f / 255.0f; float result = GainCalc.CalcRatio(255.0f, 200.0f, 0.5f); - Assert.AreEqual(expected, result, 1e-6f); + Assert.That(result, Is.EqualTo(expected).Within(1e-6f)); } /// @@ -95,7 +95,7 @@ public void CalcRatio_value255_updateRateを変えても結果が同じ() { float result05 = GainCalc.CalcRatio(255.0f, 200.0f, 0.5f); float result10 = GainCalc.CalcRatio(255.0f, 200.0f, 1.0f); - Assert.AreEqual(result05, result10, 1e-6f, "value==255 のとき updateRate によらず結果が同じ"); + Assert.That(result10, Is.EqualTo(result05).Within(1e-6f), "value==255 のとき updateRate によらず結果が同じ"); } // --------------------------------------------------------------- @@ -110,7 +110,7 @@ [Test] public void CalcRatio_targetがvalueより小さい_updateRate0_5_比率が1未満になる() { float result = GainCalc.CalcRatio(200.0f, 100.0f, 0.5f); - Assert.AreEqual(0.75f, result, 1e-6f); + Assert.That(result, Is.EqualTo(0.75f).Within(1e-6f)); } // --------------------------------------------------------------- @@ -125,7 +125,7 @@ [Test] public void CalcRatio_updateRate0_比率は常に1() { float result = GainCalc.CalcRatio(100.0f, 200.0f, 0.0f); - Assert.AreEqual(1.0f, result, 1e-6f); + Assert.That(result, Is.EqualTo(1.0f).Within(1e-6f)); } // --------------------------------------------------------------- @@ -140,7 +140,7 @@ public void CalcRatio_value0_戻り値はInfinityまたはNaN_例外は出ない() { float result = GainCalc.CalcRatio(0.0f, 200.0f, 0.5f); // float(0 除算) は例外を投げずに Infinity / NaN を返す - Assert.IsTrue(float.IsInfinity(result) || float.IsNaN(result), + Assert.That(float.IsInfinity(result) || float.IsNaN(result), Is.True, "value=0 のとき戻り値は Infinity または NaN になる(例外は出ない)"); } } diff --git a/TIASshot.Tests/ImageStatsTests.cs b/TIASshot.Tests/ImageStatsTests.cs index 4d9b0cf..9c5722a 100644 --- a/TIASshot.Tests/ImageStatsTests.cs +++ b/TIASshot.Tests/ImageStatsTests.cs @@ -33,12 +33,12 @@ var stats = ImageStats.Calc(mat); // Assert: ch別 mean / max - Assert.AreEqual(100.0, stats.MeanB, 1e-3, "MeanB = 100"); - Assert.AreEqual(100.0, stats.MeanG, 1e-3, "MeanG = 100"); - Assert.AreEqual(100.0, stats.MeanR, 1e-3, "MeanR = 100"); - Assert.AreEqual(100.0, stats.MaxB, 1e-3, "MaxB = 100"); - Assert.AreEqual(100.0, stats.MaxG, 1e-3, "MaxG = 100"); - Assert.AreEqual(100.0, stats.MaxR, 1e-3, "MaxR = 100"); + Assert.That(stats.MeanB, Is.EqualTo(100.0).Within(1e-3), "MeanB = 100"); + Assert.That(stats.MeanG, Is.EqualTo(100.0).Within(1e-3), "MeanG = 100"); + Assert.That(stats.MeanR, Is.EqualTo(100.0).Within(1e-3), "MeanR = 100"); + Assert.That(stats.MaxB, Is.EqualTo(100.0).Within(1e-3), "MaxB = 100"); + Assert.That(stats.MaxG, Is.EqualTo(100.0).Within(1e-3), "MaxG = 100"); + Assert.That(stats.MaxR, Is.EqualTo(100.0).Within(1e-3), "MaxR = 100"); } } @@ -54,12 +54,12 @@ var stats = ImageStats.Calc(mat); // Assert - Assert.AreEqual(50.0, stats.MeanB, 1e-3, "MeanB = 50"); - Assert.AreEqual(120.0, stats.MeanG, 1e-3, "MeanG = 120"); - Assert.AreEqual(200.0, stats.MeanR, 1e-3, "MeanR = 200"); - Assert.AreEqual(50.0, stats.MaxB, 1e-3, "MaxB = 50"); - Assert.AreEqual(120.0, stats.MaxG, 1e-3, "MaxG = 120"); - Assert.AreEqual(200.0, stats.MaxR, 1e-3, "MaxR = 200"); + Assert.That(stats.MeanB, Is.EqualTo(50.0).Within(1e-3), "MeanB = 50"); + Assert.That(stats.MeanG, Is.EqualTo(120.0).Within(1e-3), "MeanG = 120"); + Assert.That(stats.MeanR, Is.EqualTo(200.0).Within(1e-3), "MeanR = 200"); + Assert.That(stats.MaxB, Is.EqualTo(50.0).Within(1e-3), "MaxB = 50"); + Assert.That(stats.MaxG, Is.EqualTo(120.0).Within(1e-3), "MaxG = 120"); + Assert.That(stats.MaxR, Is.EqualTo(200.0).Within(1e-3), "MaxR = 200"); } } @@ -79,14 +79,14 @@ var stats = ImageStats.Calc(mat); // Assert: MaxB=50, MaxG=60, MaxR=70(2画素の最大値) - Assert.AreEqual(50.0, stats.MaxB, 1e-3, "MaxB は 2 画素の最大値 50"); - Assert.AreEqual(60.0, stats.MaxG, 1e-3, "MaxG は 2 画素の最大値 60"); - Assert.AreEqual(70.0, stats.MaxR, 1e-3, "MaxR は 2 画素の最大値 70"); + Assert.That(stats.MaxB, Is.EqualTo(50.0).Within(1e-3), "MaxB は 2 画素の最大値 50"); + Assert.That(stats.MaxG, Is.EqualTo(60.0).Within(1e-3), "MaxG は 2 画素の最大値 60"); + Assert.That(stats.MaxR, Is.EqualTo(70.0).Within(1e-3), "MaxR は 2 画素の最大値 70"); // Assert: MeanB=(10+50)/2=30, MeanG=(20+60)/2=40, MeanR=(30+70)/2=50 - Assert.AreEqual(30.0, stats.MeanB, 1e-3, "MeanB = (10+50)/2 = 30"); - Assert.AreEqual(40.0, stats.MeanG, 1e-3, "MeanG = (20+60)/2 = 40"); - Assert.AreEqual(50.0, stats.MeanR, 1e-3, "MeanR = (30+70)/2 = 50"); + Assert.That(stats.MeanB, Is.EqualTo(30.0).Within(1e-3), "MeanB = (10+50)/2 = 30"); + Assert.That(stats.MeanG, Is.EqualTo(40.0).Within(1e-3), "MeanG = (20+60)/2 = 40"); + Assert.That(stats.MeanR, Is.EqualTo(50.0).Within(1e-3), "MeanR = (30+70)/2 = 50"); } } @@ -102,7 +102,7 @@ public void Calc_全画素同一値100_飽和率0() { using (var mat = new Mat(2, 2, MatType.CV_8UC3, new Scalar(100, 100, 100))) { var stats = ImageStats.Calc(mat); - Assert.AreEqual(0.0, stats.SaturatedRatio, 1e-6, "全輝度 100 → 飽和率 0"); + Assert.That(stats.SaturatedRatio, Is.EqualTo(0.0).Within(1e-6), "全輝度 100 → 飽和率 0"); } } @@ -114,7 +114,7 @@ public void Calc_全画素255_飽和率1_0() { using (var mat = new Mat(2, 2, MatType.CV_8UC3, new Scalar(255, 255, 255))) { var stats = ImageStats.Calc(mat); - Assert.AreEqual(1.0, stats.SaturatedRatio, 1e-6, "全画素 255 → 飽和率 1.0"); + Assert.That(stats.SaturatedRatio, Is.EqualTo(1.0).Within(1e-6), "全画素 255 → 飽和率 1.0"); } } @@ -126,7 +126,7 @@ public void Calc_全画素255_p99は255() { using (var mat = new Mat(2, 2, MatType.CV_8UC3, new Scalar(255, 255, 255))) { var stats = ImageStats.Calc(mat); - Assert.AreEqual(255.0, stats.P99, 1e-3, "全画素 255 → p99 = 255"); + Assert.That(stats.P99, Is.EqualTo(255.0).Within(1e-3), "全画素 255 → p99 = 255"); } } @@ -138,7 +138,7 @@ public void Calc_全画素同一値100_p99は100() { using (var mat = new Mat(2, 2, MatType.CV_8UC3, new Scalar(100, 100, 100))) { var stats = ImageStats.Calc(mat); - Assert.AreEqual(100.0, stats.P99, 1e-3, "全輝度 100 → p99 = 100"); + Assert.That(stats.P99, Is.EqualTo(100.0).Within(1e-3), "全輝度 100 → p99 = 100"); } } @@ -160,7 +160,7 @@ var stats = ImageStats.Calc(mat); // Assert: 4画素中1画素飽和 → 1/4 = 0.25 - Assert.AreEqual(0.25, stats.SaturatedRatio, 1e-6, "4画素中1画素飽和 → SaturatedRatio = 0.25"); + Assert.That(stats.SaturatedRatio, Is.EqualTo(0.25).Within(1e-6), "4画素中1画素飽和 → SaturatedRatio = 0.25"); } } @@ -177,7 +177,7 @@ var stats = ImageStats.Calc(mat); // Assert: 輝度ベースでは飽和なし - Assert.AreEqual(0.0, stats.SaturatedRatio, 1e-6, + Assert.That(stats.SaturatedRatio, Is.EqualTo(0.0).Within(1e-6), "R=255のみ → BGR2GRAY ≒ 76 < 254 → 輝度ベース飽和率 = 0"); } } @@ -190,7 +190,7 @@ public void Calc_G255のみ_輝度ベースでは飽和しない() { using (var mat = new Mat(1, 1, MatType.CV_8UC3, new Scalar(0, 255, 0))) { var stats = ImageStats.Calc(mat); - Assert.AreEqual(0.0, stats.SaturatedRatio, 1e-6, + Assert.That(stats.SaturatedRatio, Is.EqualTo(0.0).Within(1e-6), "G=255のみ → BGR2GRAY ≒ 150 < 254 → 飽和率 = 0"); } } @@ -207,7 +207,7 @@ public void CalcPercentile_全画素同一値150_p50は150() { using (var gray = new Mat(4, 4, MatType.CV_8U, new Scalar(150))) { double p50 = ImageStats.CalcPercentile(gray, 50.0); - Assert.AreEqual(150.0, p50, 1e-3, "全画素 150 → p50 = 150"); + Assert.That(p50, Is.EqualTo(150.0).Within(1e-3), "全画素 150 → p50 = 150"); } } @@ -219,7 +219,7 @@ public void CalcPercentile_全画素同一値200_p99は200() { using (var gray = new Mat(4, 4, MatType.CV_8U, new Scalar(200))) { double p99 = ImageStats.CalcPercentile(gray, 99.0); - Assert.AreEqual(200.0, p99, 1e-3, "全画素 200 → p99 = 200"); + Assert.That(p99, Is.EqualTo(200.0).Within(1e-3), "全画素 200 → p99 = 200"); } } @@ -231,7 +231,7 @@ public void CalcPercentile_全画素同一値100_p100は100() { using (var gray = new Mat(4, 4, MatType.CV_8U, new Scalar(100))) { double p100 = ImageStats.CalcPercentile(gray, 100.0); - Assert.AreEqual(100.0, p100, 1e-3, "全画素 100 → p100 = 100"); + Assert.That(p100, Is.EqualTo(100.0).Within(1e-3), "全画素 100 → p100 = 100"); } } @@ -251,7 +251,7 @@ double p50 = ImageStats.CalcPercentile(gray, 50.0); // Assert: threshold = 2 * 0.5 = 1.0。bin[100]=1.0 → cumulative=1.0 >= 1.0 → 100 - Assert.AreEqual(100.0, p50, 1e-3, "p50: bin[100]=1 → cumulative=1 >= threshold=1 → p50=100"); + Assert.That(p50, Is.EqualTo(100.0).Within(1e-3), "p50: bin[100]=1 → cumulative=1 >= threshold=1 → p50=100"); } } @@ -267,7 +267,7 @@ gray.At(0, 1) = 200; double p99 = ImageStats.CalcPercentile(gray, 99.0); - Assert.AreEqual(200.0, p99, 1e-3, "p99=200(上位1%に 200 が含まれるため)"); + Assert.That(p99, Is.EqualTo(200.0).Within(1e-3), "p99=200(上位1%に 200 が含まれるため)"); } } @@ -284,7 +284,7 @@ // Arrange: 0行0列の CV_8U using (var gray = new Mat(0, 0, MatType.CV_8U)) { double result = ImageStats.CalcPercentile(gray, 99.0); - Assert.AreEqual(0.0, result, 1e-6, "空 Mat → 0.0 を返す"); + Assert.That(result, Is.EqualTo(0.0).Within(1e-6), "空 Mat → 0.0 を返す"); } } @@ -310,12 +310,12 @@ string json = ImageStats.BuildJson(meta, null); // Assert: null / 空でない - Assert.IsNotNull(json, "json が null であってはならない"); - Assert.IsNotEmpty(json, "json が空文字列であってはならない"); + Assert.That(json, Is.Not.Null, "json が null であってはならない"); + Assert.That(json, Is.Not.Empty, "json が空文字列であってはならない"); // Assert: '{' / '}' で囲まれている(最低限の JSON 外枠) - Assert.IsTrue(json.TrimStart().StartsWith("{"), "JSON は '{' で始まる"); - Assert.IsTrue(json.TrimEnd().EndsWith("}"), "JSON は '}' で終わる"); + Assert.That(json.TrimStart().StartsWith("{"), Is.True, "JSON は '{' で始まる"); + Assert.That(json.TrimEnd().EndsWith("}"), Is.True, "JSON は '}' で終わる"); } /// @@ -332,8 +332,8 @@ string json = ImageStats.BuildJson(meta, null); // bool は JSON の true / false リテラルになること - StringAssert.Contains("\"flag_on\": true", json, "true が literal true になること"); - StringAssert.Contains("\"flag_off\": false", json, "false が literal false になること"); + Assert.That(json, Does.Contain("\"flag_on\": true"), "true が literal true になること"); + Assert.That(json, Does.Contain("\"flag_off\": false"), "false が literal false になること"); } /// @@ -348,7 +348,7 @@ string json = ImageStats.BuildJson(meta, null); // int は引用符なしの数値リテラル - StringAssert.Contains("\"num_images\": 10", json, "int は数値リテラルになること"); + Assert.That(json, Does.Contain("\"num_images\": 10"), "int は数値リテラルになること"); } /// @@ -364,9 +364,9 @@ string json = ImageStats.BuildJson(meta, null); // G6 + InvariantCulture: 1.23456789 → "1.23457"(四捨五入6桁) - StringAssert.Contains("\"val\": 1.23457", json, "double は G6 InvariantCulture で書式化される"); + Assert.That(json, Does.Contain("\"val\": 1.23457"), "double は G6 InvariantCulture で書式化される"); // ロケール依存のカンマ区切り(例: "1,23457")が混入していないこと - Assert.IsFalse(json.Contains("1,23457"), "小数点はカンマではなくピリオドを使う(InvariantCulture)"); + Assert.That(json.Contains("1,23457"), Is.False, "小数点はカンマではなくピリオドを使う(InvariantCulture)"); } /// @@ -382,7 +382,7 @@ string json = ImageStats.BuildJson(meta, null); // '"' が '\\"' にエスケープされた文字列として含まれること - StringAssert.Contains("say \\\"hello\\\"", json, "\" は \\\" にエスケープされること"); + Assert.That(json, Does.Contain("say \\\"hello\\\""), "\" は \\\" にエスケープされること"); } /// @@ -398,7 +398,7 @@ string json = ImageStats.BuildJson(meta, null); // '\' が '\\' にエスケープされた文字列として含まれること - StringAssert.Contains(@"C:\\TIAS_Data", json, @"\ は \\ にエスケープされること"); + Assert.That(json, Does.Contain(@"C:\\TIAS_Data"), @"\ は \\ にエスケープされること"); } /// @@ -427,18 +427,18 @@ string json = ImageStats.BuildJson(meta, stats); // Assert: "frame_stats" 配列が存在する - StringAssert.Contains("\"frame_stats\"", json, "frame_stats キーが存在すること"); + Assert.That(json, Does.Contain("\"frame_stats\""), "frame_stats キーが存在すること"); // Assert: フレーム番号・各フィールドが含まれる - StringAssert.Contains("\"frame\": 1", json, "frame 番号 1 が含まれること"); - StringAssert.Contains("\"saturated_ratio\"", json, "saturated_ratio キーが含まれること"); - StringAssert.Contains("\"p99_luminance\"", json, "p99_luminance キーが含まれること"); - StringAssert.Contains("\"mean_B\"", json, "mean_B キーが含まれること"); - StringAssert.Contains("\"mean_G\"", json, "mean_G キーが含まれること"); - StringAssert.Contains("\"mean_R\"", json, "mean_R キーが含まれること"); - StringAssert.Contains("\"max_B\"", json, "max_B キーが含まれること"); - StringAssert.Contains("\"max_G\"", json, "max_G キーが含まれること"); - StringAssert.Contains("\"max_R\"", json, "max_R キーが含まれること"); + Assert.That(json, Does.Contain("\"frame\": 1"), "frame 番号 1 が含まれること"); + Assert.That(json, Does.Contain("\"saturated_ratio\""), "saturated_ratio キーが含まれること"); + Assert.That(json, Does.Contain("\"p99_luminance\""), "p99_luminance キーが含まれること"); + Assert.That(json, Does.Contain("\"mean_B\""), "mean_B キーが含まれること"); + Assert.That(json, Does.Contain("\"mean_G\""), "mean_G キーが含まれること"); + Assert.That(json, Does.Contain("\"mean_R\""), "mean_R キーが含まれること"); + Assert.That(json, Does.Contain("\"max_B\""), "max_B キーが含まれること"); + Assert.That(json, Does.Contain("\"max_G\""), "max_G キーが含まれること"); + Assert.That(json, Does.Contain("\"max_R\""), "max_R キーが含まれること"); } /// @@ -454,8 +454,8 @@ string json = ImageStats.BuildJson(meta, stats); - StringAssert.Contains("\"frame\": 1", json, "1枚目のフレーム番号は 1"); - StringAssert.Contains("\"frame\": 2", json, "2枚目のフレーム番号は 2"); + Assert.That(json, Does.Contain("\"frame\": 1"), "1枚目のフレーム番号は 1"); + Assert.That(json, Does.Contain("\"frame\": 2"), "2枚目のフレーム番号は 2"); } /// @@ -467,7 +467,7 @@ string json = ImageStats.BuildJson(meta, null); - Assert.IsFalse(json.Contains("frame_stats"), + Assert.That(json.Contains("frame_stats"), Is.False, "stats が null のとき frame_stats キーは生成されない"); } @@ -480,7 +480,7 @@ string json = ImageStats.BuildJson(meta, new List()); - Assert.IsFalse(json.Contains("frame_stats"), + Assert.That(json.Contains("frame_stats"), Is.False, "stats が空リストのとき frame_stats キーは生成されない"); } @@ -498,7 +498,7 @@ string json = ImageStats.BuildJson(meta, stats); // G6 で 0.0 → "0" - StringAssert.Contains("\"saturated_ratio\": 0", json, + Assert.That(json, Does.Contain("\"saturated_ratio\": 0"), "飽和率 0 は JSON に 0 としてシリアライズされること"); } diff --git a/TIASshot.Tests/IoUtilCombineSaveFilePathTests.cs b/TIASshot.Tests/IoUtilCombineSaveFilePathTests.cs index 39f93e6..f4b8564 100644 --- a/TIASshot.Tests/IoUtilCombineSaveFilePathTests.cs +++ b/TIASshot.Tests/IoUtilCombineSaveFilePathTests.cs @@ -38,7 +38,7 @@ var result = IoUtil.CombineSaveFilePath(_saveFolder, filename); // Assert - Assert.IsTrue(IsUnderSaveFolder(result), + Assert.That(IsUnderSaveFolder(result), Is.True, $"保存先が保存フォルダの外を指している: {Path.GetFullPath(result)}"); } @@ -54,7 +54,7 @@ var result = IoUtil.CombineSaveFilePath(_saveFolder, filename); // Assert - Assert.IsTrue(IsUnderSaveFolder(result), + Assert.That(IsUnderSaveFolder(result), Is.True, $"保存先が保存フォルダの外を指している: {Path.GetFullPath(result)}"); } @@ -78,7 +78,7 @@ var result = IoUtil.CombineSaveFilePath(_saveFolder, filename); // Assert - Assert.AreEqual(Path.Combine(_saveFolder, filename), result, + Assert.That(result, Is.EqualTo(Path.Combine(_saveFolder, filename)), "同梱 config.xml の既存値では結合結果が従来と完全一致すること"); } } diff --git a/TIASshot.Tests/IoUtilCreateSaveFolderTests.cs b/TIASshot.Tests/IoUtilCreateSaveFolderTests.cs index c0c1627..4e4d5ca 100644 --- a/TIASshot.Tests/IoUtilCreateSaveFolderTests.cs +++ b/TIASshot.Tests/IoUtilCreateSaveFolderTests.cs @@ -57,9 +57,9 @@ var result = IoUtil.CreateSaveFolder(note); // Assert - Assert.IsTrue(IsUnderBase(result), + Assert.That(IsUnderBase(result), Is.True, $"保存フォルダがベースフォルダの外に生成された: {Path.GetFullPath(result)}"); - Assert.IsFalse(Directory.Exists(Path.Combine(_rootDir, "evil")), + Assert.That(Directory.Exists(Path.Combine(_rootDir, "evil")), Is.False, "ベースフォルダ外に 'evil' ディレクトリが作られてはならない"); } @@ -77,9 +77,9 @@ "不正文字を含むデータ名で例外が発生してはならない(撮影中断の可用性影響)"); // Assert - Assert.IsNotNull(result); - Assert.IsTrue(Directory.Exists(result), "保存フォルダが生成されていること"); - Assert.IsTrue(IsUnderBase(result), "保存フォルダはベースフォルダ配下であること"); + Assert.That(result, Is.Not.Null); + Assert.That(Directory.Exists(result), Is.True, "保存フォルダが生成されていること"); + Assert.That(IsUnderBase(result), Is.True, "保存フォルダはベースフォルダ配下であること"); } /// @@ -94,9 +94,9 @@ var result = IoUtil.CreateSaveFolder(note); // Assert - Assert.IsTrue(Directory.Exists(result), "保存フォルダが生成されていること"); - Assert.IsTrue(IsUnderBase(result), "保存フォルダはベースフォルダ配下であること"); - StringAssert.EndsWith("-subject01", Path.GetFileName(result), + Assert.That(Directory.Exists(result), Is.True, "保存フォルダが生成されていること"); + Assert.That(IsUnderBase(result), Is.True, "保存フォルダはベースフォルダ配下であること"); + Assert.That(Path.GetFileName(result), Does.EndWith("-subject01"), "フォルダ名末尾にデータ名がそのまま保持されること"); } } diff --git a/TIASshot.Tests/IoUtilSaveImageTests.cs b/TIASshot.Tests/IoUtilSaveImageTests.cs index 4103e30..4c56a45 100644 --- a/TIASshot.Tests/IoUtilSaveImageTests.cs +++ b/TIASshot.Tests/IoUtilSaveImageTests.cs @@ -42,8 +42,8 @@ var result = IoUtil.SaveImage(path, img); // Assert - Assert.IsFalse(result, "存在しないフォルダへの保存失敗が false で報告されること"); - Assert.IsFalse(File.Exists(path), "ファイルが生成されていないこと"); + Assert.That(result, Is.False, "存在しないフォルダへの保存失敗が false で報告されること"); + Assert.That(File.Exists(path), Is.False, "ファイルが生成されていないこと"); } } @@ -60,8 +60,8 @@ var result = IoUtil.SaveImage(path, img); // Assert - Assert.IsTrue(result, "正常な保存では true を返すこと"); - Assert.IsTrue(File.Exists(path), "ファイルが生成されていること"); + Assert.That(result, Is.True, "正常な保存では true を返すこと"); + Assert.That(File.Exists(path), Is.True, "ファイルが生成されていること"); } } } diff --git a/TIASshot.Tests/IoUtilTests.cs b/TIASshot.Tests/IoUtilTests.cs index d770ef5..2a290f3 100644 --- a/TIASshot.Tests/IoUtilTests.cs +++ b/TIASshot.Tests/IoUtilTests.cs @@ -32,16 +32,15 @@ IoUtil.SaveMatToCsv(_csvPath, src); using (var loaded = IoUtil.LoadMatFromCsv(_csvPath)) { // Assert - Assert.IsNotNull(loaded, "ロード結果が null であってはならない"); - Assert.AreEqual(src.Rows, loaded.Rows, "行数が一致すること"); - Assert.AreEqual(src.Cols, loaded.Cols, "列数が一致すること"); + Assert.That(loaded, Is.Not.Null, "ロード結果が null であってはならない"); + Assert.That(loaded.Rows, Is.EqualTo(src.Rows), "行数が一致すること"); + Assert.That(loaded.Cols, Is.EqualTo(src.Cols), "列数が一致すること"); for (int row = 0; row < src.Rows; row++) { for (int col = 0; col < src.Cols; col++) { - Assert.AreEqual( - src.At(row, col), + Assert.That( loaded.At(row, col), - 1e-6, + Is.EqualTo(src.At(row, col)).Within(1e-6), $"[{row},{col}] の値が ±1e-6 以内で一致すること"); } } @@ -63,8 +62,8 @@ IoUtil.SaveMatToCsv(_csvPath, src); using (var loaded = IoUtil.LoadMatFromCsv(_csvPath)) { // Assert - Assert.IsNotNull(loaded); - Assert.AreEqual(Pi, loaded.At(0, 0), 1e-6); + Assert.That(loaded, Is.Not.Null); + Assert.That(loaded.At(0, 0), Is.EqualTo(Pi).Within(1e-6)); } } } @@ -87,10 +86,10 @@ // Act using (var loaded = IoUtil.LoadMatFromCsv(_csvPath)) { // Assert - Assert.IsNotNull(loaded); - Assert.AreEqual(96.32301186, loaded.At(0, 0), 1e-6); - Assert.AreEqual(112.325025, loaded.At(0, 1), 1e-6); - Assert.AreEqual(186.5234201, loaded.At(0, 2), 1e-6); + Assert.That(loaded, Is.Not.Null); + Assert.That(loaded.At(0, 0), Is.EqualTo(96.32301186).Within(1e-6)); + Assert.That(loaded.At(0, 1), Is.EqualTo(112.325025).Within(1e-6)); + Assert.That(loaded.At(0, 2), Is.EqualTo(186.5234201).Within(1e-6)); } } finally { System.Threading.Thread.CurrentThread.CurrentCulture = original; @@ -118,7 +117,7 @@ // Assert var line = File.ReadAllLines(_csvPath)[0]; - Assert.AreEqual("1.2345678,-2.5000000", line, + Assert.That(line, Is.EqualTo("1.2345678,-2.5000000"), "ロケールによらずピリオド小数・カンマ列区切りで出力すること"); } } finally { @@ -144,8 +143,8 @@ // Assert var lines = File.ReadAllLines(_csvPath); - Assert.AreEqual("1.2345670,-2.3456780,0.0000010", lines[0]); - Assert.AreEqual("100.0000000,-0.5000000,999.9999990", lines[1]); + Assert.That(lines[0], Is.EqualTo("1.2345670,-2.3456780,0.0000010")); + Assert.That(lines[1], Is.EqualTo("100.0000000,-0.5000000,999.9999990")); } } finally { System.Threading.Thread.CurrentThread.CurrentCulture = original; @@ -163,16 +162,16 @@ "..", "..", "..", "..", "TIASshot")); var srgbPath = Path.Combine(repoDir, "tcc_srgb.csv"); var xyzPath = Path.Combine(repoDir, "tcc_xyz.csv"); - Assert.IsTrue(File.Exists(srgbPath), $"同梱 tcc_srgb.csv が見つからない: {srgbPath}"); - Assert.IsTrue(File.Exists(xyzPath), $"同梱 tcc_xyz.csv が見つからない: {xyzPath}"); + Assert.That(File.Exists(srgbPath), Is.True, $"同梱 tcc_srgb.csv が見つからない: {srgbPath}"); + Assert.That(File.Exists(xyzPath), Is.True, $"同梱 tcc_xyz.csv が見つからない: {xyzPath}"); using (var srgb = IoUtil.LoadMatFromCsv(srgbPath)) using (var xyz = IoUtil.LoadMatFromCsv(xyzPath)) { - Assert.IsNotNull(srgb, "tcc_srgb.csv が読めること"); - Assert.IsNotNull(xyz, "tcc_xyz.csv が読めること"); - Assert.AreEqual(3, srgb.Cols, "tcc_srgb.csv は 3 列であること"); - Assert.AreEqual(3, xyz.Cols, "tcc_xyz.csv は 3 列であること"); - Assert.AreEqual(96.32301186, srgb.At(0, 0), 1e-6, + Assert.That(srgb, Is.Not.Null, "tcc_srgb.csv が読めること"); + Assert.That(xyz, Is.Not.Null, "tcc_xyz.csv が読めること"); + Assert.That(srgb.Cols, Is.EqualTo(3), "tcc_srgb.csv は 3 列であること"); + Assert.That(xyz.Cols, Is.EqualTo(3), "tcc_xyz.csv は 3 列であること"); + Assert.That(srgb.At(0, 0), Is.EqualTo(96.32301186).Within(1e-6), "tcc_srgb.csv の先頭要素が従来値で読めること"); } } @@ -186,7 +185,7 @@ var result = IoUtil.LoadMatFromCsv("does_not_exist_xyz.csv"); // Assert - Assert.IsNull(result, "存在しないファイルのロードは null を返すこと"); + Assert.That(result, Is.Null, "存在しないファイルのロードは null を返すこと"); } // --------------------------------------------------------------- diff --git a/TIASshot.Tests/MemBenchSupportTests.cs b/TIASshot.Tests/MemBenchSupportTests.cs index ff12edc..22bade2 100644 --- a/TIASshot.Tests/MemBenchSupportTests.cs +++ b/TIASshot.Tests/MemBenchSupportTests.cs @@ -33,9 +33,9 @@ using (var src = new Mat(2, 2, MatType.CV_8UC3, new Scalar(50, 100, 150))) using (var dst = MemBenchSupport.ConvertImageLeaky(corrector, src, conv)) { // Assert: 型・サイズ - Assert.AreEqual(MatType.CV_8UC3, dst.Type(), "出力型は CV_8UC3"); - Assert.AreEqual(2, dst.Rows, "出力行数は入力と同じ(2)"); - Assert.AreEqual(2, dst.Cols, "出力列数は入力と同じ(2)"); + Assert.That(dst.Type(), Is.EqualTo(MatType.CV_8UC3), "出力型は CV_8UC3"); + Assert.That(dst.Rows, Is.EqualTo(2), "出力行数は入力と同じ(2)"); + Assert.That(dst.Cols, Is.EqualTo(2), "出力列数は入力と同じ(2)"); } } } @@ -57,9 +57,9 @@ for (int row = 0; row < dst.Rows; row++) { for (int col = 0; col < dst.Cols; col++) { var pixel = dst.At(row, col); - Assert.AreEqual(0, pixel.Item0, $"row={row}, col={col}: B は 0"); - Assert.AreEqual(0, pixel.Item1, $"row={row}, col={col}: G は 0"); - Assert.AreEqual(0, pixel.Item2, $"row={row}, col={col}: R は 0"); + Assert.That(pixel.Item0, Is.EqualTo(0), $"row={row}, col={col}: B は 0"); + Assert.That(pixel.Item1, Is.EqualTo(0), $"row={row}, col={col}: G は 0"); + Assert.That(pixel.Item2, Is.EqualTo(0), $"row={row}, col={col}: R は 0"); } } }