diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md index c99c897..14c5401 100644 --- a/.claude/rules/testing.md +++ b/.claude/rules/testing.md @@ -32,7 +32,9 @@ | 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(...)`(これらは変更不要) | +| 例外 | `Assert.Throws((Action)(() => ...))` / `Assert.DoesNotThrow((Action)(() => ...))` | + +- **例外系のラムダは `(Action)` にキャストする**.NUnit 4.6 は `TestDelegate` 版(`[Obsolete]`)と `Action` 版(`[OverloadResolutionPriority]`)の両方を持ち,LangVersion 7.3 のテストプロジェクトでは優先度属性が解釈されず CS0121(呼び出しが曖昧)になる.LangVersion は古い VS / Build Tools との互換のため上げない(2026-09-29 の NUnit 4.6.1 移行で 16 箇所を対応). - **引数の順序に注意する**.Classic は `(expected, actual)` だが制約モデルは `(actual, 制約)` である.とくに `Does.Contain` は第 1 引数が**検査対象**で,期待する部分文字列は制約の側に入る(逆にすると意味が反転したまま通ってしまう場合がある). - 浮動小数点の比較で `.Within(...)` を落とさないこと.厳密比較になりフレーキーになる. diff --git a/CLAUDE.md b/CLAUDE.md index 820f5ec..4b75c57 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ ## 開発進捗 -最新: テンプレートを `00dd94e` に同期(`/setup` のフェーズごとコミット・環境構築の実行).本プロジェクトは実機依存のため検証プロファイルは作らず Phase 1b はスキップ運用.#31(ArUco API 移行)は実機確認待ちの PR #36 として引き続き保留中 +最新: 2 回目の `/deps-update`(#44 マージ)と NUnit 4.6.1 への移行(#27 の追従).#31(ArUco API 移行)は実機確認待ちの PR #36 として引き続き保留中 ※ 本欄は**最新ステップ 1 行のみ上書き更新**.詳細な進捗履歴(動機・設計判断・失敗パターン)は [docs/PROGRESS.md](docs/PROGRESS.md) に追記する.運用ルールは `.claude/rules/progress-log.md` を参照(該当ファイル編集時に自動ロードされる). ## 必須ルール(コード実装時) diff --git a/TIASshot.Tests/BitmapUtilTests.cs b/TIASshot.Tests/BitmapUtilTests.cs index 4a89d1b..0198304 100644 --- a/TIASshot.Tests/BitmapUtilTests.cs +++ b/TIASshot.Tests/BitmapUtilTests.cs @@ -202,7 +202,7 @@ SetIndexedPixel(src, 3, 3, 255); Bitmap dst = null; - Assert.DoesNotThrow(() => dst = BitmapUtil.FastClone(src), + Assert.DoesNotThrow((Action)(() => dst = BitmapUtil.FastClone(src)), "8bppIndexed を渡しても例外をスローしないこと"); try { diff --git a/TIASshot.Tests/ColorCorrectorTests.cs b/TIASshot.Tests/ColorCorrectorTests.cs index bc1594f..8642ef9 100644 --- a/TIASshot.Tests/ColorCorrectorTests.cs +++ b/TIASshot.Tests/ColorCorrectorTests.cs @@ -385,7 +385,7 @@ using (var conv = CreateIdentityLikeConvMat()) { // Act: 例外が発生しないことも検証(解放済み Mat へのアクセスがないこと) Mat dst = null; - Assert.DoesNotThrow(() => dst = corrector.ConvertImage(src, conv), + Assert.DoesNotThrow((System.Action)(() => dst = corrector.ConvertImage(src, conv)), $"呼び出し {call + 1} 回目で例外が発生した"); // Assert: 出力が正しいこと(解放済み Mat からの読み出しでないことの確認) diff --git a/TIASshot.Tests/ConfigTests.cs b/TIASshot.Tests/ConfigTests.cs index 8dd14ee..c5c3498 100644 --- a/TIASshot.Tests/ConfigTests.cs +++ b/TIASshot.Tests/ConfigTests.cs @@ -78,7 +78,7 @@ /// [Test] public void GetFloat_存在しないキー_ArgumentExceptionをスロー() { - Assert.Throws(() => Config.GetFloat("NoSuchKey")); + Assert.Throws((Action)(() => Config.GetFloat("NoSuchKey"))); } /// @@ -86,7 +86,7 @@ /// [Test] public void GetInt_存在しないキー_ArgumentExceptionをスロー() { - Assert.Throws(() => Config.GetInt("NoSuchKey")); + Assert.Throws((Action)(() => Config.GetInt("NoSuchKey"))); } /// @@ -94,7 +94,7 @@ /// [Test] public void GetString_存在しないキー_ArgumentExceptionをスロー() { - Assert.Throws(() => Config.GetString("NoSuchKey")); + Assert.Throws((Action)(() => Config.GetString("NoSuchKey"))); } /// @@ -112,7 +112,7 @@ /// [Test] public void GetInt_数値でない値_ArgumentExceptionをスロー() { - Assert.Throws(() => Config.GetInt("BadNumVal")); + Assert.Throws((Action)(() => Config.GetInt("BadNumVal"))); } /// @@ -120,7 +120,7 @@ /// [Test] public void GetFloat_数値でない値_ArgumentExceptionをスロー() { - Assert.Throws(() => Config.GetFloat("BadNumVal")); + Assert.Throws((Action)(() => Config.GetFloat("BadNumVal"))); } /// @@ -128,7 +128,7 @@ /// [Test] public void GetInt_空の値_ArgumentExceptionをスロー() { - Assert.Throws(() => Config.GetInt("EmptyVal")); + Assert.Throws((Action)(() => Config.GetInt("EmptyVal"))); } /// @@ -172,10 +172,10 @@ "Calib/Reference/B", "Calib/Reference/G", "Calib/Reference/R", }; foreach (var key in intKeys) { - Assert.DoesNotThrow(() => Config.GetInt(key), $"GetInt(\"{key}\") が例外を投げた"); + Assert.DoesNotThrow((Action)(() => Config.GetInt(key)), $"GetInt(\"{key}\") が例外を投げた"); } foreach (var key in floatKeys) { - Assert.DoesNotThrow(() => Config.GetFloat(key), $"GetFloat(\"{key}\") が例外を投げた"); + Assert.DoesNotThrow((Action)(() => Config.GetFloat(key)), $"GetFloat(\"{key}\") が例外を投げた"); } // ゼロ除算・校正停止に直結する値が有効値で読めることを固定する Assert.That(Config.GetInt("Calib/UpdateInterval"), Is.Not.EqualTo(0)); diff --git a/TIASshot.Tests/ImageStatsTests.cs b/TIASshot.Tests/ImageStatsTests.cs index 9c5722a..8032426 100644 --- a/TIASshot.Tests/ImageStatsTests.cs +++ b/TIASshot.Tests/ImageStatsTests.cs @@ -512,7 +512,7 @@ [Test] public void Calc_null_ArgumentNullExceptionをスローする() { Assert.Throws( - () => ImageStats.Calc(null), + (Action)(() => ImageStats.Calc(null)), "null Mat → ArgumentNullException"); } @@ -524,7 +524,7 @@ public void Calc_CV8UC1Mat_ArgumentExceptionをスローする() { using (var gray = new Mat(2, 2, MatType.CV_8U, new Scalar(100))) { Assert.Throws( - () => ImageStats.Calc(gray), + (Action)(() => ImageStats.Calc(gray)), "CV_8UC1 → ArgumentException(CV_8UC3 以外は不可)"); } } @@ -537,7 +537,7 @@ public void Calc_CV64FC3Mat_ArgumentExceptionをスローする() { using (var mat = new Mat(2, 2, MatType.CV_64FC3)) { Assert.Throws( - () => ImageStats.Calc(mat), + (Action)(() => ImageStats.Calc(mat)), "CV_64FC3 → ArgumentException(CV_8UC3 以外は不可)"); } } @@ -552,7 +552,7 @@ [Test] public void CalcPercentile_null_ArgumentNullExceptionをスローする() { Assert.Throws( - () => ImageStats.CalcPercentile(null, 99.0), + (Action)(() => ImageStats.CalcPercentile(null, 99.0)), "null Mat → ArgumentNullException"); } @@ -564,7 +564,7 @@ public void CalcPercentile_CV8UC3Mat_ArgumentExceptionをスローする() { using (var bgr = new Mat(2, 2, MatType.CV_8UC3, new Scalar(100, 100, 100))) { Assert.Throws( - () => ImageStats.CalcPercentile(bgr, 99.0), + (Action)(() => ImageStats.CalcPercentile(bgr, 99.0)), "CV_8UC3 → ArgumentException(CV_8U 以外は不可)"); } } diff --git a/TIASshot.Tests/IoUtilCreateSaveFolderTests.cs b/TIASshot.Tests/IoUtilCreateSaveFolderTests.cs index 4e4d5ca..1a70c47 100644 --- a/TIASshot.Tests/IoUtilCreateSaveFolderTests.cs +++ b/TIASshot.Tests/IoUtilCreateSaveFolderTests.cs @@ -73,7 +73,7 @@ // Act string result = null; - Assert.DoesNotThrow(() => { result = IoUtil.CreateSaveFolder(note); }, + Assert.DoesNotThrow((Action)(() => { result = IoUtil.CreateSaveFolder(note); }), "不正文字を含むデータ名で例外が発生してはならない(撮影中断の可用性影響)"); // Assert diff --git a/TIASshot.Tests/TIASshot.Tests.csproj b/TIASshot.Tests/TIASshot.Tests.csproj index 1e4452b..1ec99e6 100644 --- a/TIASshot.Tests/TIASshot.Tests.csproj +++ b/TIASshot.Tests/TIASshot.Tests.csproj @@ -1,5 +1,6 @@ + @@ -41,8 +42,8 @@ ..\packages\Microsoft.CodeCoverage.18.10.1\lib\net462\Microsoft.VisualStudio.CodeCoverage.Shim.dll True - - ..\packages\NUnit.3.14.0\lib\net45\nunit.framework.dll + + ..\packages\NUnit.4.6.1\lib\net462\nunit.framework.dll ..\packages\OpenCvSharp4.4.10.0.20241108\lib\net48\OpenCvSharp.dll @@ -65,6 +66,10 @@ ..\packages\System.Runtime.CompilerServices.Unsafe.6.1.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll True + + ..\packages\System.Threading.Tasks.Extensions.4.6.3\lib\net462\System.Threading.Tasks.Extensions.dll + True + @@ -106,7 +111,10 @@ + + + \ No newline at end of file diff --git a/TIASshot.Tests/packages.config b/TIASshot.Tests/packages.config index 54db0b0..e00ab8d 100644 --- a/TIASshot.Tests/packages.config +++ b/TIASshot.Tests/packages.config @@ -2,7 +2,7 @@ - + @@ -10,4 +10,6 @@ + + \ No newline at end of file diff --git "a/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" "b/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" index 7a9aff8..69b1fb7 100644 --- "a/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" +++ "b/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" @@ -19,20 +19,21 @@ **.NET 補完ライブラリ** -- `System.Buffers` (4.5.1) -- `System.Drawing.Common` (8.0.0) -- `System.Memory` (4.5.5) -- `System.Numerics.Vectors` (4.5.0) -- `System.Runtime.CompilerServices.Unsafe` (6.0.0) -- `System.ValueTuple` (4.5.0) +- `System.Buffers` (4.6.1) +- `System.Drawing.Common` (8.0.31) +- `System.Memory` (4.6.3) +- `System.Numerics.Vectors` (4.6.1) +- `System.Runtime.CompilerServices.Unsafe` (6.1.2) +- `System.ValueTuple` (4.6.2) ## テストプロジェクト TIASshot.Tests (Test Project) テストプロジェクトも `packages.config` で管理する(本体と同じレガシー形式・x64). -- `NUnit` (3.14.0): テストフレームワーク -- `NUnit3TestAdapter` (4.5.0): テストランナー連携(Visual Studio / vstest) -- `Microsoft.NET.Test.Sdk` (17.8.0): テスト実行基盤 +- `NUnit` (4.6.1): テストフレームワーク + - net48 向けの依存として `System.Threading.Tasks.Extensions` (4.6.3)・`System.ValueTuple` (4.6.2) も参照する +- `NUnit3TestAdapter` (4.6.0): テストランナー連携(Visual Studio / vstest) +- `Microsoft.NET.Test.Sdk` (17.14.1): テスト実行基盤(依存として `Microsoft.CodeCoverage` 18.10.1 が入る) - ※ `OpenCvSharp4` / `OpenCvSharp4.runtime.win` (4.10.0) も参照する.`Mat` 演算はネイティブ DLL に依存するため,テストプロジェクトも **x64** でビルドする. ## 外部 SDK(別途インストールが必要) (External SDKs) diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 0f8bbdd..7ceed8b 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -146,3 +146,9 @@ - 上流は個別のガード追加に留めず,「共通層のファイルはチーム層ファイルの存在を前提にしてはならない」を `/sync-template` の不変条件として明文化し,AST で共通層テストを検査するメタテストを追加した(メタテストは `.claude/tests/` 配下のため本プロジェクトには配布されない).同種の退行は今後テンプレート側で止まる. - [x] **テンプレートを最新版に同期(`/setup` のフェーズごとコミットと環境構築の実行)** (2026-09-29): `/sync-template` で programming-template を `3db9db5` → `00dd94e` に追従.変更は `/setup` 系(skill・GUIDE_01/02)と CLAUDE.md「Git 運用」の自律コミット例外への `/setup` 追加のみで,立ち上げ済みの本プロジェクトのコードへの影響は無い.台帳登録・未登録改変ともに 0 件. + +- [x] **2 回目の `/deps-update` と NUnit 4.6.1 への移行(#27 の追従)** (2026-09-29): 依存更新の巡回で,マイナー/パッチのグループ PR #44(Test.Sdk 17.14.1・NUnit3TestAdapter 4.6.0・System.* 4.6 系・System.Drawing.Common 8.0.31)をローカル検証(x64 クリーンビルド+テスト全緑)でマージした.メジャーの #45(System.Drawing.Common 10)・#46(Test.Sdk 18)は前回と同じく,他 PR の解決結果が csproj に混入してビルド不能だったため見送り(#46 は ignore を投稿,#45 は OpenCvSharp 4.13 が 10 系を要求するため #36 の後に一括追従).続けて #27 を `/implement` で追従し,テストプロジェクトを NUnit 4.6.1 に上げた. + - 前回(2026-08-28)の判断どおり,制約モデルへの先行移行が効いてクラシック Assert の書き換えは 0 件で済んだ. + - 失敗パターン: 代わりに NUnit 4.6 固有の CS0121 が出た.`Assert.Throws`/`DoesNotThrow` が `TestDelegate` 版(Obsolete)と `Action` 版(`[OverloadResolutionPriority]`)を併せ持ち,LangVersion 7.3 では優先度属性が効かずラムダの解決が曖昧になる.LangVersion を上げると古い VS / Build Tools でビルドできなくなるため,`(Action)` キャストで解消し,書き方を testing.md に明記した. + - 移行前後で検出テスト名一覧(124 件,うち `[Explicit]` 2 件)が完全一致すること,キャストした 16 箇所がミューテーションで正しく失敗することを確認済み. + - 後段: #27 はこのブランチの取り込み後にクローズしてよい.#31(PR #36)の実機確認待ちは継続.