#if HWTEST
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using NUnit.Framework;
namespace TIASshot.Tests {
/// <summary>
/// 実機テストの判断ロジック(HwTestJudge)のテスト(層①.SDK・UI に依存しない純粋関数).
///
/// 仕様: PLAN_06「検査項目」「守ること」・.claude/verify-profile.md「実機テスト」・HwTestJudge の各関数の契約
/// - preview: フレームレートの下限.close-preview: 所要時間の上限.ウォッチドッグは全体の上限を優先
/// - exposure-gain: 露光は Linear なら ×0.5/×2,Log2Step なら最も近い 2^n から ±1 段(範囲内に収める).
/// ゲインは範囲の幅の ±10%.露光は比(1 段下げ ≦ 0.8・上げ ≧ 1.25,確認した向きはすべて期待どおり),
/// ゲインは差(≧ 3,片側だけでも合格).動かした側が飽和(飽和画素の割合 > 1%)していれば,その向きは確認しない.
/// 両方とも確認できなければ FAIL
/// - 基準探しの判断の順番: 範囲の端 → 測れない → 中間に入った → 飛び越えた → 段数の上限 → 続ける
/// - light: 点灯と消灯の差 ≧ 100.復元: 読み戻しの相対誤差 1%(ゲインは範囲の幅 × 0.1% との大きい方)
/// - チャート不要の検査では校正を止める.終了コード 2/1/0,作業フォルダは keep 指定または 1・3 のとき残す
/// 実測の例は .verify/hwtest/run-20261008-133812/hwtest-result.txt(DFK 33UX178)から採った.
/// 本クラスは HWTEST 構成(Debug|x64)でのみコンパイルされる.
/// </summary>
[TestFixture]
public class HwTestJudgeTests {
private const double Eps = 1e-9;
private static HwTestMeasurement M(double mean, double saturatedFraction) {
return new HwTestMeasurement { Mean = mean, SaturatedFraction = saturatedFraction, MeanSaturatedFraction = saturatedFraction, Count = 8 };
}
private static double NextExp(double current, double min, double max, HwTestValueScale scale, int direction) {
return HwTestJudge.NextExposure(current, min, max, scale, direction,
HwTestThresholds.ExposureLogStep, HwTestThresholds.ExposureDownFactor, HwTestThresholds.ExposureUpFactor);
}
private static HwTestBaselineSearchDecision Decide(double mean, double sat, int direction, bool changed, int stepsDone) {
return HwTestJudge.DecideBaselineSearch(mean, sat, direction, changed, stepsDone, 12, 30, 220, 0.01);
}
// ================================================================
// フレームレート・しきい値
// ================================================================
[Test]
public void FrameRate_フレーム数を秒で割る() {
Assert.That(HwTestJudge.FrameRate(42, TimeSpan.FromSeconds(3)), Is.EqualTo(14.0).Within(Eps));
}
[Test]
public void FrameRate_時間が0_0() {
Assert.That(HwTestJudge.FrameRate(42, TimeSpan.Zero), Is.EqualTo(0.0));
}
[Test]
public void FrameRate_時間が負_0() {
Assert.That(HwTestJudge.FrameRate(42, TimeSpan.FromSeconds(-1)), Is.EqualTo(0.0));
}
[Test]
public void FrameRate_フレーム0_0() {
Assert.That(HwTestJudge.FrameRate(0, TimeSpan.FromSeconds(3)), Is.EqualTo(0.0));
}
[Test]
public void MeetsMinFrameRate_下限ちょうど_合格() {
Assert.That(HwTestJudge.MeetsMinFrameRate(10.0, 10.0), Is.True);
}
[Test]
public void MeetsMinFrameRate_下限未満_不合格() {
Assert.That(HwTestJudge.MeetsMinFrameRate(9.99, 10.0), Is.False);
}
[Test]
public void MeetsMinFrameRate_NaN_不合格() {
Assert.That(HwTestJudge.MeetsMinFrameRate(double.NaN, 10.0), Is.False);
}
[Test]
public void MeetsMinFrameRate_実測13_28fps_下限10で合格() {
// 実測: 13.28 fps(42 フレーム / 3.16 秒)
Assert.That(HwTestJudge.MeetsMinFrameRate(HwTestJudge.FrameRate(42, TimeSpan.FromSeconds(3.16)), HwTestThresholds.MinPreviewFps), Is.True);
}
[Test]
public void WithinLimit_上限ちょうど_以内() {
Assert.That(HwTestJudge.WithinLimit(TimeSpan.FromMilliseconds(1000), TimeSpan.FromMilliseconds(1000)), Is.True);
}
[Test]
public void WithinLimit_上限超え_超過() {
Assert.That(HwTestJudge.WithinLimit(TimeSpan.FromMilliseconds(1001), TimeSpan.FromMilliseconds(1000)), Is.False);
}
[Test]
public void FindOverdue_上限内_None() {
Assert.That(HwTestJudge.FindOverdue(TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(10), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(60)),
Is.EqualTo(HwTestOverdue.None));
}
[Test]
public void FindOverdue_上限ちょうど_None() {
Assert.That(HwTestJudge.FindOverdue(TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10), TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(60)),
Is.EqualTo(HwTestOverdue.None));
}
[Test]
public void FindOverdue_項目の上限超え_Item() {
Assert.That(HwTestJudge.FindOverdue(TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(10), TimeSpan.FromSeconds(61), TimeSpan.FromSeconds(60)),
Is.EqualTo(HwTestOverdue.Item));
}
[Test]
public void FindOverdue_全体と項目の両方超え_全体を優先() {
Assert.That(HwTestJudge.FindOverdue(TimeSpan.FromMinutes(11), TimeSpan.FromMinutes(10), TimeSpan.FromSeconds(61), TimeSpan.FromSeconds(60)),
Is.EqualTo(HwTestOverdue.Overall));
}
[Test]
public void FindOverdue_実行中の項目なし_項目の上限を見ない() {
Assert.That(HwTestJudge.FindOverdue(TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(10), TimeSpan.FromHours(1), null),
Is.EqualTo(HwTestOverdue.None));
}
// ================================================================
// 露光・ゲインの段の計算
// ================================================================
[Test]
public void NextExposure_Linear_下げる_半分() {
Assert.That(NextExp(0.01, 0.0001, 1, HwTestValueScale.Linear, -1), Is.EqualTo(0.005).Within(Eps));
}
[Test]
public void NextExposure_Linear_上げる_2倍() {
Assert.That(NextExp(0.01, 0.0001, 1, HwTestValueScale.Linear, +1), Is.EqualTo(0.02).Within(Eps));
}
[Test]
public void NextExposure_Linear_上げて最大を超える_最大に収める() {
Assert.That(NextExp(0.8, 0.0001, 1, HwTestValueScale.Linear, +1), Is.EqualTo(1.0));
}
[Test]
public void NextExposure_Linear_下げて最小を下回る_最小に収める() {
Assert.That(NextExp(0.0003, 0.0002, 1, HwTestValueScale.Linear, -1), Is.EqualTo(0.0002));
}
[Test]
public void NextExposure_Log2Step_下げる_最も近い2のn乗から1段下() {
// 実測: 露光 0.016667(最も近い 2^n は 2^-6 = 0.015625)→ 下げた 0.007813(2^-7)
Assert.That(NextExp(0.016667, 2e-5, 60, HwTestValueScale.Log2Step, -1), Is.EqualTo(Math.Pow(2, -7)).Within(1e-12));
}
[Test]
public void NextExposure_Log2Step_上げる_最も近い2のn乗から1段上() {
// 実測: 露光 0.016667 → 上げた 0.03125(2^-5)
Assert.That(NextExp(0.016667, 2e-5, 60, HwTestValueScale.Log2Step, +1), Is.EqualTo(Math.Pow(2, -5)).Within(1e-12));
}
[Test]
public void NextExposure_Log2Step_ちょうど2のn乗_そこから1段() {
Assert.That(NextExp(0.015625, 2e-5, 60, HwTestValueScale.Log2Step, +1), Is.EqualTo(0.03125).Within(1e-12));
}
[Test]
public void NextExposure_Log2Step_最大を超える_最大に収める() {
Assert.That(NextExp(0.5, 2e-5, 0.6, HwTestValueScale.Log2Step, +1), Is.EqualTo(0.6));
}
[Test]
public void NextExposure_Log2Step_最小を下回る_最小に収める() {
Assert.That(NextExp(3e-5, 2e-5, 60, HwTestValueScale.Log2Step, -1), Is.EqualTo(2e-5));
}
[Test]
public void NextExposure_向きが0_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => NextExp(0.01, 0.0001, 1, HwTestValueScale.Linear, 0)));
}
[Test]
public void NextExposure_最小が最大より大きい_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => NextExp(0.01, 1, 0.0001, HwTestValueScale.Linear, 1)));
}
[Test]
public void NextExposure_現在値がNaN_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => NextExp(double.NaN, 0.0001, 1, HwTestValueScale.Linear, 1)));
}
[Test]
public void NextExposure_範囲が無限大_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => NextExp(0.01, 0, double.PositiveInfinity, HwTestValueScale.Linear, 1)));
}
[Test]
public void NextExposure_Log2Stepで現在値が0_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => NextExp(0, 0, 1, HwTestValueScale.Log2Step, 1)));
}
[Test]
public void NextExposure_Log2Stepで段の量が0_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() =>
HwTestJudge.NextExposure(0.01, 0, 1, HwTestValueScale.Log2Step, 1, 0, 0.5, 2)));
}
[Test]
public void NextExposure_未知の種類_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => NextExp(0.01, 0, 1, (HwTestValueScale)99, 1)));
}
[Test]
public void AlignExposure_Linear_そのまま() {
Assert.That(HwTestJudge.AlignExposure(0.016667, 2e-5, 60, HwTestValueScale.Linear), Is.EqualTo(0.016667));
}
[Test]
public void AlignExposure_Log2Step_最も近い2のn乗に合わせる() {
// 実測: 元の 0.016667 に最も近い 2^n(0.015625)に合わせた
Assert.That(HwTestJudge.AlignExposure(0.016667, 2e-5, 60, HwTestValueScale.Log2Step), Is.EqualTo(0.015625).Within(1e-12));
}
[Test]
public void AlignExposure_Log2Step_最も近い2のn乗が最小未満_範囲内で最も近い2のn乗() {
// 0.02 に最も近いのは 2^-6(0.015625)だが最小 0.02 未満.範囲 [0.02, 1] の中で最も近いのは 2^-5
Assert.That(HwTestJudge.AlignExposure(0.02, 0.02, 1, HwTestValueScale.Log2Step), Is.EqualTo(0.03125).Within(1e-12));
}
[Test]
public void AlignExposure_Log2Step_最も近い2のn乗が最大超え_範囲内で最も近い2のn乗() {
// 2.9 に最も近いのは 4(2^2)だが最大 2.9 を超える.範囲内で最も近いのは 2(2^1)
Assert.That(HwTestJudge.AlignExposure(2.9, 0.1, 2.9, HwTestValueScale.Log2Step), Is.EqualTo(2.0).Within(1e-12));
}
[Test]
public void AlignExposure_Log2Step_最大がちょうど2のn乗_最大に合わせる() {
// 7 に最も近いのは 8 = 最大(log の丸め誤差で 1 段ずれないこと)
Assert.That(HwTestJudge.AlignExposure(7, 0.1, 8, HwTestValueScale.Log2Step), Is.EqualTo(8.0).Within(1e-12));
}
[Test]
public void AlignExposure_Log2Step_範囲内に2のn乗が無い_そのまま() {
Assert.That(HwTestJudge.AlignExposure(0.35, 0.3, 0.4, HwTestValueScale.Log2Step), Is.EqualTo(0.35));
}
[Test]
public void AlignExposure_Log2Stepで現在値が0_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.AlignExposure(0, 0, 1, HwTestValueScale.Log2Step)));
}
[Test]
public void AlignExposure_範囲が不正_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.AlignExposure(0.5, 1, 0, HwTestValueScale.Linear)));
}
[Test]
public void ScaleSetting_倍率を掛ける() {
Assert.That(HwTestJudge.ScaleSetting(0.4, 0, 1, 0.5), Is.EqualTo(0.2).Within(Eps));
}
[Test]
public void ScaleSetting_範囲外_範囲内に収める() {
Assert.That(HwTestJudge.ScaleSetting(0.6, 0, 1, 2), Is.EqualTo(1.0));
}
[Test]
public void ScaleSetting_現在値0で上げる_最小から範囲の幅の5パーセント() {
Assert.That(HwTestJudge.ScaleSetting(0, 0, 10, 2), Is.EqualTo(0.5).Within(Eps));
}
[Test]
public void ScaleSetting_現在値0で下げる_変わらない() {
Assert.That(HwTestJudge.ScaleSetting(0, 0, 10, 0.5), Is.EqualTo(0.0));
}
[Test]
public void ScaleSetting_倍率0_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.ScaleSetting(0.5, 0, 1, 0)));
}
[Test]
public void ScaleSetting_倍率NaN_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.ScaleSetting(0.5, 0, 1, double.NaN)));
}
[Test]
public void StepSetting_範囲の幅の10パーセント上げる() {
// 実測: ゲイン 1(範囲 0〜48)→ 上げた 5.8
Assert.That(HwTestJudge.StepSetting(1, 0, 48, HwTestThresholds.GainStepFraction), Is.EqualTo(5.8).Within(Eps));
}
[Test]
public void StepSetting_下げて最小を下回る_最小に収める() {
// 実測: ゲイン 1(範囲 0〜48)→ 下げた 0
Assert.That(HwTestJudge.StepSetting(1, 0, 48, -HwTestThresholds.GainStepFraction), Is.EqualTo(0.0));
}
[Test]
public void StepSetting_上げて最大を超える_最大に収める() {
Assert.That(HwTestJudge.StepSetting(47, 0, 48, HwTestThresholds.GainStepFraction), Is.EqualTo(48.0));
}
[Test]
public void StepSetting_割合NaN_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.StepSetting(1, 0, 48, double.NaN)));
}
[Test]
public void StepSetting_範囲が不正_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.StepSetting(1, 48, 0, 0.1)));
}
// ================================================================
// 輝度・飽和
// ================================================================
[Test]
public void FrameStats_BGR_3チャネルの平均() {
var rows = new byte[] { 10, 20, 30, 40, 50, 60 };
var s = HwTestJudge.FrameStats(rows, 1, 2, 6, 3, 1, 254);
Assert.That(s.Mean, Is.EqualTo(35.0).Within(Eps));
}
[Test]
public void FrameStats_飽和なし_割合0() {
var rows = new byte[] { 253, 253, 253, 0, 0, 0 };
var s = HwTestJudge.FrameStats(rows, 1, 2, 6, 3, 1, 254);
Assert.That(s.SaturatedFraction, Is.EqualTo(0.0));
}
[Test]
public void FrameStats_いずれかのチャネルが254以上_飽和画素として数える() {
// 2 画素のうち 1 画素の R だけが 254
var rows = new byte[] { 0, 0, 254, 100, 100, 100 };
var s = HwTestJudge.FrameStats(rows, 1, 2, 6, 3, 1, HwTestThresholds.SaturatedPixelLevel);
Assert.That(s.SaturatedFraction, Is.EqualTo(0.5).Within(Eps));
}
[Test]
public void FrameStats_4チャネル_アルファを読まない() {
var rows = new byte[] { 0, 0, 0, 255, 30, 30, 30, 255 };
var s = HwTestJudge.FrameStats(rows, 1, 2, 8, 4, 1, 254);
Assert.That(new[] { s.Mean, s.SaturatedFraction }, Is.EqualTo(new[] { 15.0, 0.0 }).Within(Eps));
}
[Test]
public void FrameStats_1チャネル_先頭チャネルの平均() {
var rows = new byte[] { 10, 30, 50, 70 };
var s = HwTestJudge.FrameStats(rows, 2, 2, 2, 1, 1, 254);
Assert.That(s.Mean, Is.EqualTo(40.0).Within(Eps));
}
[Test]
public void FrameStats_間引き_指定画素ごとに読む() {
// 1 チャネル・4 画素で 2 画素ごと → 画素 0 と 2 だけを読む
var rows = new byte[] { 10, 200, 30, 200 };
var s = HwTestJudge.FrameStats(rows, 1, 4, 4, 1, 2, 254);
Assert.That(s.Mean, Is.EqualTo(20.0).Within(Eps));
}
[Test]
public void FrameStats_行の詰め物_読まない() {
// 1 行 = 2 画素 × 3 バイト + 詰め物 2 バイト(255)
var rows = new byte[] { 10, 10, 10, 20, 20, 20, 255, 255, 30, 30, 30, 40, 40, 40, 255, 255 };
var s = HwTestJudge.FrameStats(rows, 2, 2, 8, 3, 1, 254);
Assert.That(new[] { s.Mean, s.SaturatedFraction }, Is.EqualTo(new[] { 25.0, 0.0 }).Within(Eps));
}
[Test]
public void FrameStats_rowsがnull_ArgumentException() {
Assert.Throws<ArgumentNullException>((Action)(() => HwTestJudge.FrameStats(null, 1, 1, 3, 3, 1, 254)));
}
[Test]
public void FrameStats_1画素のバイト数が5_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.FrameStats(new byte[10], 1, 2, 10, 5, 1, 254)));
}
[Test]
public void FrameStats_1行のバイト数が不足_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.FrameStats(new byte[6], 1, 2, 5, 3, 1, 254)));
}
[Test]
public void FrameStats_画素データが不足_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.FrameStats(new byte[6], 2, 2, 6, 3, 1, 254)));
}
[Test]
public void FrameStats_間引き0_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.FrameStats(new byte[6], 1, 2, 6, 3, 0, 254)));
}
[Test]
public void FrameStats_画素なし_ArgumentException() {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.FrameStats(new byte[6], 0, 2, 6, 3, 1, 254)));
}
[Test]
public void IsSaturated_しきい値ちょうど_飽和でない() {
Assert.That(HwTestJudge.IsSaturated(0.01, 0.01), Is.False);
}
[Test]
public void IsSaturated_しきい値超え_飽和() {
Assert.That(HwTestJudge.IsSaturated(0.0101, 0.01), Is.True);
}
[Test]
public void IsSaturated_NaN_飽和でない() {
Assert.That(HwTestJudge.IsSaturated(double.NaN, 0.01), Is.False);
}
[TestCase(30.0)]
[TestCase(125.0)]
[TestCase(220.0)]
public void IsMidBrightness_範囲内と境界_true(double mean) {
Assert.That(HwTestJudge.IsMidBrightness(mean, 30, 220), Is.True);
}
[TestCase(29.99)]
[TestCase(220.01)]
[TestCase(double.NaN)]
public void IsMidBrightness_範囲外とNaN_false(double mean) {
Assert.That(HwTestJudge.IsMidBrightness(mean, 30, 220), Is.False);
}
[Test]
public void IsBaselineCandidate_中間で飽和なし_true() {
// 実測: 露光 0.015625 の平均輝度 158.94・飽和画素の割合 0.00% は基準にできる
Assert.That(HwTestJudge.IsBaselineCandidate(158.94, 0.0, 30, 220, 0.01), Is.True);
}
[Test]
public void IsBaselineCandidate_中間でも飽和_false() {
Assert.That(HwTestJudge.IsBaselineCandidate(200, 0.05, 30, 220, 0.01), Is.False);
}
[Test]
public void IsBaselineCandidate_飽和割合NaN_false() {
Assert.That(HwTestJudge.IsBaselineCandidate(150, double.NaN, 30, 220, 0.01), Is.False);
}
[Test]
public void IsBaselineCandidate_明るすぎ_false() {
Assert.That(HwTestJudge.IsBaselineCandidate(230, 0.0, 30, 220, 0.01), Is.False);
}
[Test]
public void Summarize_平均輝度は平均() {
var m = HwTestJudge.Summarize(new[] { new HwTestFrameStats(100, 0.0), new HwTestFrameStats(110, 0.04) });
Assert.That(m.Mean, Is.EqualTo(105.0).Within(Eps));
}
[Test]
public void Summarize_飽和割合は最大() {
var m = HwTestJudge.Summarize(new[] { new HwTestFrameStats(100, 0.0), new HwTestFrameStats(110, 0.04), new HwTestFrameStats(100, 0.02) });
Assert.That(m.SaturatedFraction, Is.EqualTo(0.04).Within(Eps));
}
[Test]
public void Summarize_飽和割合の平均を参考に持つ() {
var m = HwTestJudge.Summarize(new[] { new HwTestFrameStats(100, 0.0), new HwTestFrameStats(110, 0.04) });
Assert.That(m.MeanSaturatedFraction, Is.EqualTo(0.02).Within(Eps));
}
[Test]
public void Summarize_フレーム数() {
var m = HwTestJudge.Summarize(new[] { new HwTestFrameStats(100, 0.0), new HwTestFrameStats(110, 0.04) });
Assert.That(m.Count, Is.EqualTo(2));
}
[Test]
public void Summarize_空_測定できない() {
var m = HwTestJudge.Summarize(new HwTestFrameStats[0]);
Assert.That(new object[] { double.IsNaN(m.Mean), double.IsNaN(m.SaturatedFraction), m.Count }, Is.EqualTo(new object[] { true, true, 0 }));
}
[Test]
public void Summarize_null_測定できない() {
var m = HwTestJudge.Summarize(null);
Assert.That(new object[] { double.IsNaN(m.Mean), m.Count }, Is.EqualTo(new object[] { true, 0 }));
}
// ================================================================
// 基準探し
// ================================================================
[Test]
public void BaselineSearchDirection_明るすぎ_下げる() {
Assert.That(HwTestJudge.BaselineSearchDirection(230, 0.0, 30, 220, 0.01), Is.EqualTo(-1));
}
[Test]
public void BaselineSearchDirection_中間でも飽和_下げる() {
Assert.That(HwTestJudge.BaselineSearchDirection(200, 0.05, 30, 220, 0.01), Is.EqualTo(-1));
}
[Test]
public void BaselineSearchDirection_暗すぎ_上げる() {
Assert.That(HwTestJudge.BaselineSearchDirection(20, 0.0, 30, 220, 0.01), Is.EqualTo(1));
}
[Test]
public void BaselineSearchDirection_基準にできる明るさ_動かさない() {
Assert.That(HwTestJudge.BaselineSearchDirection(158.94, 0.0, 30, 220, 0.01), Is.EqualTo(0));
}
[Test]
public void BaselineSearchDirection_測定できない_動かさない() {
Assert.That(HwTestJudge.BaselineSearchDirection(double.NaN, double.NaN, 30, 220, 0.01), Is.EqualTo(0));
}
[Test]
public void DecideBaselineSearch_設定が変わらない_範囲の端を最優先() {
// 測定できない・中間に入った,のどちらにも当たる値でも範囲の端が先
Assert.That(Decide(double.NaN, double.NaN, -1, false, 1), Is.EqualTo(HwTestBaselineSearchDecision.StopRangeEnd));
}
[Test]
public void DecideBaselineSearch_設定が変わらない_中間でも範囲の端() {
Assert.That(Decide(150, 0.0, -1, false, 1), Is.EqualTo(HwTestBaselineSearchDecision.StopRangeEnd));
}
[Test]
public void DecideBaselineSearch_平均輝度NaN_測れない() {
Assert.That(Decide(double.NaN, 0.0, -1, true, 1), Is.EqualTo(HwTestBaselineSearchDecision.StopNotMeasured));
}
[Test]
public void DecideBaselineSearch_飽和割合NaN_測れない() {
Assert.That(Decide(150, double.NaN, -1, true, 1), Is.EqualTo(HwTestBaselineSearchDecision.StopNotMeasured));
}
[Test]
public void DecideBaselineSearch_中間に入った_Found() {
Assert.That(Decide(150, 0.0, -1, true, 1), Is.EqualTo(HwTestBaselineSearchDecision.Found));
}
[Test]
public void DecideBaselineSearch_段数の上限で中間に入った_上限よりFoundが先() {
Assert.That(Decide(150, 0.0, -1, true, 12), Is.EqualTo(HwTestBaselineSearchDecision.Found));
}
[Test]
public void DecideBaselineSearch_下げる向きで暗すぎになった_飛び越えた() {
Assert.That(Decide(20, 0.0, -1, true, 1), Is.EqualTo(HwTestBaselineSearchDecision.StopOvershoot));
}
[Test]
public void DecideBaselineSearch_上げる向きで明るすぎになった_飛び越えた() {
Assert.That(Decide(230, 0.0, 1, true, 1), Is.EqualTo(HwTestBaselineSearchDecision.StopOvershoot));
}
[Test]
public void DecideBaselineSearch_上げる向きで飽和した_飛び越えた() {
Assert.That(Decide(200, 0.05, 1, true, 1), Is.EqualTo(HwTestBaselineSearchDecision.StopOvershoot));
}
[Test]
public void DecideBaselineSearch_段数の上限で飛び越えた_上限より飛び越えたが先() {
Assert.That(Decide(20, 0.0, -1, true, 12), Is.EqualTo(HwTestBaselineSearchDecision.StopOvershoot));
}
[Test]
public void DecideBaselineSearch_段数の上限でまだ明るすぎ_上限() {
Assert.That(Decide(230, 0.0, -1, true, 12), Is.EqualTo(HwTestBaselineSearchDecision.StopMaxSteps));
}
[Test]
public void DecideBaselineSearch_まだ明るすぎ_続ける() {
Assert.That(Decide(230, 0.0, -1, true, 3), Is.EqualTo(HwTestBaselineSearchDecision.Continue));
}
[Test]
public void DecideBaselineSearch_まだ暗すぎ_続ける() {
Assert.That(Decide(20, 0.0, 1, true, 3), Is.EqualTo(HwTestBaselineSearchDecision.Continue));
}
[Test]
public void ChooseBaselineIndex_中間に最も近い段() {
var samples = new List<HwTestBaselineSample> {
new HwTestBaselineSample(1, 250, 0), new HwTestBaselineSample(2, 228, 0), new HwTestBaselineSample(3, 10, 0),
};
Assert.That(HwTestJudge.ChooseBaselineIndex(samples, 30, 220, 0.01), Is.EqualTo(1));
}
[Test]
public void ChooseBaselineIndex_飽和していない段を優先() {
// 段 0 は中間の範囲内だが飽和,段 1 は暗すぎるが飽和していない
var samples = new List<HwTestBaselineSample> {
new HwTestBaselineSample(1, 200, 0.05), new HwTestBaselineSample(2, 5, 0),
};
Assert.That(HwTestJudge.ChooseBaselineIndex(samples, 30, 220, 0.01), Is.EqualTo(1));
}
[Test]
public void ChooseBaselineIndex_すべて飽和_その中で中間に最も近い段() {
var samples = new List<HwTestBaselineSample> {
new HwTestBaselineSample(1, 250, 0.5), new HwTestBaselineSample(2, 230, 0.2),
};
Assert.That(HwTestJudge.ChooseBaselineIndex(samples, 30, 220, 0.01), Is.EqualTo(1));
}
[Test]
public void ChooseBaselineIndex_NaNは除く() {
var samples = new List<HwTestBaselineSample> {
new HwTestBaselineSample(1, double.NaN, double.NaN), new HwTestBaselineSample(2, 10, 0),
};
Assert.That(HwTestJudge.ChooseBaselineIndex(samples, 30, 220, 0.01), Is.EqualTo(1));
}
[Test]
public void ChooseBaselineIndex_同じ近さ_先の段() {
var samples = new List<HwTestBaselineSample> {
new HwTestBaselineSample(1, 240, 0), new HwTestBaselineSample(2, 10, 0),
};
Assert.That(HwTestJudge.ChooseBaselineIndex(samples, 30, 220, 0.01), Is.EqualTo(0));
}
[Test]
public void ChooseBaselineIndex_すべてNaN_マイナス1() {
var samples = new List<HwTestBaselineSample> { new HwTestBaselineSample(1, double.NaN, double.NaN) };
Assert.That(HwTestJudge.ChooseBaselineIndex(samples, 30, 220, 0.01), Is.EqualTo(-1));
}
[Test]
public void ChooseBaselineIndex_空_マイナス1() {
Assert.That(HwTestJudge.ChooseBaselineIndex(new List<HwTestBaselineSample>(), 30, 220, 0.01), Is.EqualTo(-1));
}
[Test]
public void ChooseBaselineIndex_null_マイナス1() {
Assert.That(HwTestJudge.ChooseBaselineIndex(null, 30, 220, 0.01), Is.EqualTo(-1));
}
// ================================================================
// 方向の判定(露光: 比・すべて確認した向きが期待どおり)
// ================================================================
[Test]
public void ExposureCriteria_比で見て下げる0_8以下_上げる1_25以上_すべて確認() {
var c = HwTestJudge.ExposureCriteria();
Assert.That(new object[] { c.UseRatio, c.LowerLimit, c.RaiseLimit, c.MaxSaturatedFraction, c.RequireAllChecked },
Is.EqualTo(new object[] { true, 0.8, 1.25, 0.01, true }));
}
[Test]
public void JudgeDirection_露光_実測_下げる側が期待どおりで合格() {
// 実測: 基準 158.92 → 下げた 86.63(比 0.545).上げた 210.14 は飽和割合 70.18%
var r = HwTestJudge.JudgeDirection(M(158.92, 0.0), M(86.63, 0.0), M(210.14, 0.7018), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Pass, Is.True);
}
[Test]
public void JudgeDirection_露光_実測_下げる側を確認して期待どおり() {
var r = HwTestJudge.JudgeDirection(M(158.92, 0.0), M(86.63, 0.0), M(210.14, 0.7018), true, true, HwTestJudge.ExposureCriteria());
Assert.That(new[] { r.LowerChecked, r.LowerOk }, Is.EqualTo(new[] { true, true }));
}
[Test]
public void JudgeDirection_露光_実測_上げた側が飽和_確認しない() {
var r = HwTestJudge.JudgeDirection(M(158.92, 0.0), M(86.63, 0.0), M(210.14, 0.7018), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.RaiseChecked, Is.False);
}
[Test]
public void JudgeDirection_露光_実測_説明に飽和のため確認しないと飽和割合が出る() {
var r = HwTestJudge.JudgeDirection(M(158.92, 0.0), M(86.63, 0.0), M(210.14, 0.7018), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Summary, Does.Contain("飽和のため確認しない(飽和割合 70.18%"));
}
[Test]
public void JudgeDirection_露光_比が境界ちょうど_合格() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(80, 0), M(125, 0), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Pass, Is.True);
}
[Test]
public void JudgeDirection_露光_下げても暗くならない_不合格() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(81, 0), M(150, 0), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Pass, Is.False);
}
[Test]
public void JudgeDirection_露光_上げても明るくならない_不合格() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(50, 0), M(124, 0), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Pass, Is.False);
}
[Test]
public void JudgeDirection_露光_上げた側が飽和_比が足りなくても不合格にしない() {
// 飽和で頭打ちになり比 1.1 だが,飽和しているので確認しない(下げる側の合格で合格)
var r = HwTestJudge.JudgeDirection(M(100, 0), M(50, 0), M(110, 0.3), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Pass, Is.True);
}
[Test]
public void JudgeDirection_露光_上げた側が飽和_比を満たしても期待どおりとしない() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(50, 0), M(200, 0.3), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.RaiseOk, Is.False);
}
[Test]
public void JudgeDirection_露光_下げた側が飽和_確認しない() {
var r = HwTestJudge.JudgeDirection(M(200, 0), M(150, 0.05), M(255, 0), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.LowerChecked, Is.False);
}
[Test]
public void JudgeDirection_露光_下げた側が飽和_説明に飽和のため確認しないが出る() {
var r = HwTestJudge.JudgeDirection(M(200, 0), M(150, 0.05), M(255, 0), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Summary, Does.Contain("下げる: 飽和のため確認しない(飽和割合"));
}
[Test]
public void JudgeDirection_露光_飽和割合がしきい値ちょうど_確認する() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(50, 0), M(150, 0.01), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.RaiseChecked, Is.True);
}
[Test]
public void JudgeDirection_露光_両側とも飽和_不合格() {
var r = HwTestJudge.JudgeDirection(M(200, 0), M(150, 0.05), M(255, 0.5), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Pass, Is.False);
}
[Test]
public void JudgeDirection_露光_両側とも確認できない_説明に出る() {
var r = HwTestJudge.JudgeDirection(M(200, 0), M(150, 0.05), M(255, 0.5), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Summary, Does.Contain("どちらの向きも確認できません"));
}
[Test]
public void JudgeDirection_露光_設定が変わらなかった向き_確認しない() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(100, 0), M(150, 0), false, true, HwTestJudge.ExposureCriteria());
Assert.That(r.LowerChecked, Is.False);
}
[Test]
public void JudgeDirection_露光_片側だけ設定が変わり期待どおり_合格() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(100, 0), M(150, 0), false, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Pass, Is.True);
}
[Test]
public void JudgeDirection_露光_基準が真っ暗_両側とも確認せず不合格() {
var r = HwTestJudge.JudgeDirection(M(3, 0), M(2, 0), M(8, 0), true, true, HwTestJudge.ExposureCriteria());
Assert.That(new[] { r.LowerChecked, r.RaiseChecked, r.Pass }, Is.EqualTo(new[] { false, false, false }));
}
[Test]
public void JudgeDirection_露光_基準が飽和_上げる向きを確認しない() {
var r = HwTestJudge.JudgeDirection(M(240, 0.2), M(120, 0), M(250, 0.2), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.RaiseChecked, Is.False);
}
[Test]
public void JudgeDirection_露光_下げた側が測定できない_確認しない() {
var r = HwTestJudge.JudgeDirection(M(100, 0), HwTestMeasurement.NotMeasured, M(150, 0), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.LowerChecked, Is.False);
}
[Test]
public void JudgeDirection_基準が測定できない_不合格() {
var r = HwTestJudge.JudgeDirection(HwTestMeasurement.NotMeasured, M(50, 0), M(150, 0), true, true, HwTestJudge.ExposureCriteria());
Assert.That(r.Pass, Is.False);
}
[Test]
public void JudgeDirection_基準がnull_ArgumentNullException() {
Assert.Throws<ArgumentNullException>((Action)(() =>
HwTestJudge.JudgeDirection(M(100, 0), M(50, 0), M(150, 0), true, true, null)));
}
// ================================================================
// 方向の判定(ゲイン: 差・片側だけでも合格)
// ================================================================
[Test]
public void GainCriteria_差で見て3以上_片側で合格() {
var c = HwTestJudge.GainCriteria();
Assert.That(new object[] { c.UseRatio, c.LowerLimit, c.RaiseLimit, c.MaxSaturatedFraction, c.RequireAllChecked },
Is.EqualTo(new object[] { false, 3.0, 3.0, 0.01, false }));
}
[Test]
public void JudgeDirection_ゲイン_実測_上げた側が飽和でも下げる側で合格() {
// 実測: 基準 158.88 → 下げた 143.27(差 -15.6).上げた 206.02 は飽和割合 68.37%
var r = HwTestJudge.JudgeDirection(M(158.88, 0.0), M(143.27, 0.0), M(206.02, 0.6837), true, true, HwTestJudge.GainCriteria());
Assert.That(r.Pass, Is.True);
}
[Test]
public void JudgeDirection_ゲイン_実測_上げた側は確認しない() {
var r = HwTestJudge.JudgeDirection(M(158.88, 0.0), M(143.27, 0.0), M(206.02, 0.6837), true, true, HwTestJudge.GainCriteria());
Assert.That(r.RaiseChecked, Is.False);
}
[Test]
public void JudgeDirection_ゲイン_差が境界ちょうど_期待どおり() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(97, 0), M(103, 0), true, true, HwTestJudge.GainCriteria());
Assert.That(new[] { r.LowerOk, r.RaiseOk }, Is.EqualTo(new[] { true, true }));
}
[Test]
public void JudgeDirection_ゲイン_下げる側だけ足りない_片側で合格() {
// 範囲の下端で変化が小さい(DFK 33UX178 の実測: 10→0 で差 -3.2 の付近)
var r = HwTestJudge.JudgeDirection(M(100, 0), M(99, 0), M(110, 0), true, true, HwTestJudge.GainCriteria());
Assert.That(r.Pass, Is.True);
}
[Test]
public void JudgeDirection_ゲイン_片側で合格_説明に出る() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(99, 0), M(110, 0), true, true, HwTestJudge.GainCriteria());
Assert.That(r.Summary, Does.Contain("一方の向きが期待どおりのため合格"));
}
[Test]
public void JudgeDirection_ゲイン_両側とも足りない_不合格() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(99, 0), M(102, 0), true, true, HwTestJudge.GainCriteria());
Assert.That(r.Pass, Is.False);
}
[Test]
public void JudgeDirection_ゲイン_上げた側が飽和で下げる側が足りない_不合格() {
// 上げた側は差 +50 だが飽和しているので確認しない
var r = HwTestJudge.JudgeDirection(M(100, 0), M(99, 0), M(150, 0.5), true, true, HwTestJudge.GainCriteria());
Assert.That(r.Pass, Is.False);
}
[Test]
public void JudgeDirection_ゲイン_両側とも確認できない_不合格() {
var r = HwTestJudge.JudgeDirection(M(100, 0), M(100, 0), M(150, 0.5), false, true, HwTestJudge.GainCriteria());
Assert.That(r.Pass, Is.False);
}
// ================================================================
// 光源・復元
// ================================================================
[Test]
public void JudgeLight_実測_点灯168_63消灯15_20_合格() {
Assert.That(HwTestJudge.JudgeLight(168.63, 15.20, HwTestThresholds.MinLightDelta), Is.True);
}
[Test]
public void JudgeLight_差が下限ちょうど_合格() {
Assert.That(HwTestJudge.JudgeLight(150, 50, 100), Is.True);
}
[Test]
public void JudgeLight_差が下限未満_不合格() {
Assert.That(HwTestJudge.JudgeLight(149.9, 50, 100), Is.False);
}
[Test]
public void JudgeLight_消灯の方が明るい_不合格() {
Assert.That(HwTestJudge.JudgeLight(50, 200, 100), Is.False);
}
[Test]
public void JudgeLight_NaN_不合格() {
Assert.That(HwTestJudge.JudgeLight(double.NaN, 15, 100), Is.False);
}
[Test]
public void MinLightDelta_100() {
Assert.That(HwTestThresholds.MinLightDelta, Is.EqualTo(100.0));
}
[Test]
public void IsSameSetting_相対誤差1パーセント以内_同じ() {
Assert.That(HwTestJudge.IsSameSetting(0.016667, 0.016667 * 1.005, 0.01, 0), Is.True);
}
[Test]
public void IsSameSetting_相対誤差1パーセント超え_違う() {
Assert.That(HwTestJudge.IsSameSetting(0.016667, 0.016667 * 1.02, 0.01, 0), Is.False);
}
[Test]
public void IsSameSetting_元が0でも絶対誤差の許容内_同じ() {
// ゲイン 0 dB(範囲 0〜48): 絶対誤差の許容 48 × 0.1% = 0.048
Assert.That(HwTestJudge.IsSameSetting(0, 0.04, 0.01, 48 * HwTestThresholds.GainRestoreRangeFraction), Is.True);
}
[Test]
public void IsSameSetting_元が0で絶対誤差の許容超え_違う() {
Assert.That(HwTestJudge.IsSameSetting(0, 0.05, 0.01, 48 * HwTestThresholds.GainRestoreRangeFraction), Is.False);
}
[Test]
public void IsSameSetting_相対と絶対の大きい方を許容にする() {
// 元 1 → 1.04: 相対の許容は約 0.0104 だが,絶対の許容 0.048 の方が大きい
Assert.That(HwTestJudge.IsSameSetting(1, 1.04, 0.01, 0.048), Is.True);
}
[Test]
public void IsSameSetting_NaN_違う() {
Assert.That(HwTestJudge.IsSameSetting(1, double.NaN, 0.01, 0.048), Is.False);
}
[Test]
public void RestoreTolerances_相対1パーセント_ゲインは範囲の0_1パーセント() {
Assert.That(new[] { HwTestThresholds.RestoreRelativeTolerance, HwTestThresholds.GainRestoreRangeFraction },
Is.EqualTo(new[] { 0.01, 0.001 }));
}
[Test]
public void IsRestored_許容内_戻った() {
// 実測: 最初 168.73 → 元に戻した後 168.64
Assert.That(HwTestJudge.IsRestored(168.73, 168.64, HwTestThresholds.RestoreTolerance), Is.True);
}
[Test]
public void IsRestored_許容ちょうど_戻った() {
Assert.That(HwTestJudge.IsRestored(100, 110, 10), Is.True);
}
[Test]
public void IsRestored_許容超え_戻っていない() {
Assert.That(HwTestJudge.IsRestored(100, 110.5, 10), Is.False);
}
[Test]
public void IsRestored_NaN_戻っていない() {
Assert.That(HwTestJudge.IsRestored(100, double.NaN, 10), Is.False);
}
[Test]
public void RelativeError_差を元の絶対値で割る() {
Assert.That(HwTestJudge.RelativeError(-2, -1), Is.EqualTo(0.5).Within(Eps));
}
[Test]
public void RelativeError_NaN_NaN() {
Assert.That(HwTestJudge.RelativeError(double.NaN, 1), Is.NaN);
}
[Test]
public void RelativeError_元も読み戻しも0_0() {
Assert.That(HwTestJudge.RelativeError(0, 0), Is.EqualTo(0.0));
}
[Test]
public void RelativeError_元が0で読み戻しが0でない_正の無限大() {
Assert.That(HwTestJudge.RelativeError(0, 1), Is.EqualTo(double.PositiveInfinity));
}
[Test]
public void DescribeRestoredValue_丸めない値を往復できる書式で出す() {
var v = 1.0 / 60;
Assert.That(HwTestJudge.DescribeRestoredValue("露光", v, v), Does.Contain("読み戻し " + v.ToString("R", CultureInfo.InvariantCulture)));
}
[Test]
public void DescribeRestoredValue_一致_相対誤差0パーセント() {
Assert.That(HwTestJudge.DescribeRestoredValue("露光", 0.5, 0.5), Does.Contain("相対誤差 0%"));
}
[Test]
public void DescribeRestoredValue_元が0_元が0と出る() {
Assert.That(HwTestJudge.DescribeRestoredValue("ゲイン", 0, 0.01), Does.Contain("元が 0"));
}
[Test]
public void DescribeRestoredValue_NaN_測定できないと出る() {
Assert.That(HwTestJudge.DescribeRestoredValue("ゲイン", 1, double.NaN), Does.Contain("測定できない"));
}
[Test]
public void DescribeRestoredValue_小数点がカンマの文化でもピリオドで出す() {
var saved = Thread.CurrentThread.CurrentCulture;
string text;
try {
Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE");
text = HwTestJudge.DescribeRestoredValue("露光", 0.25, 0.25);
} finally {
Thread.CurrentThread.CurrentCulture = saved;
}
Assert.That(text, Does.Contain("読み戻し 0.25(元 0.25."));
}
// ================================================================
// 校正の停止
// ================================================================
[Test]
public void ShouldSuppressCalibration_チャート不要の検査_止める() {
Assert.That(HwTestJudge.ShouldSuppressCalibration(false), Is.True);
}
[Test]
public void ShouldSuppressCalibration_チャートが必要な検査_止めない() {
Assert.That(HwTestJudge.ShouldSuppressCalibration(true), Is.False);
}
[Test]
public void IsCalibrationLeaked_止めているのに校正中_漏れ() {
Assert.That(HwTestJudge.IsCalibrationLeaked(true, true, false), Is.True);
}
[Test]
public void IsCalibrationLeaked_止めているのに校正済み_漏れ() {
Assert.That(HwTestJudge.IsCalibrationLeaked(true, false, true), Is.True);
}
[Test]
public void IsCalibrationLeaked_止めていて校正なし_漏れでない() {
Assert.That(HwTestJudge.IsCalibrationLeaked(true, false, false), Is.False);
}
[Test]
public void IsCalibrationLeaked_止めていない_校正中でも漏れでない() {
Assert.That(HwTestJudge.IsCalibrationLeaked(false, true, true), Is.False);
}
// ================================================================
// 終了コードと作業フォルダ
// ================================================================
[Test]
public void DecideExitCode_機種が見つからない_不合格数によらず2() {
Assert.That(HwTestJudge.DecideExitCode(true, 3), Is.EqualTo(2));
}
[Test]
public void DecideExitCode_不合格あり_1() {
Assert.That(HwTestJudge.DecideExitCode(false, 1), Is.EqualTo(1));
}
[Test]
public void DecideExitCode_すべて合格_0() {
Assert.That(HwTestJudge.DecideExitCode(false, 0), Is.EqualTo(0));
}
[Test]
public void ExitCodes_0合格_1不合格_2異常_3タイムアウト() {
Assert.That(new[] { HwTestExitCodes.Pass, HwTestExitCodes.Fail, HwTestExitCodes.Error, HwTestExitCodes.Timeout },
Is.EqualTo(new[] { 0, 1, 2, 3 }));
}
[TestCase(0)]
[TestCase(1)]
[TestCase(2)]
[TestCase(3)]
public void ShouldKeepWorkDir_keep指定_常に残す(int exitCode) {
Assert.That(HwTestJudge.ShouldKeepWorkDir(true, exitCode), Is.True);
}
[TestCase(1)]
[TestCase(3)]
public void ShouldKeepWorkDir_不合格とタイムアウト_残す(int exitCode) {
Assert.That(HwTestJudge.ShouldKeepWorkDir(false, exitCode), Is.True);
}
[TestCase(0)]
[TestCase(2)]
public void ShouldKeepWorkDir_合格と前提不足_消す(int exitCode) {
Assert.That(HwTestJudge.ShouldKeepWorkDir(false, exitCode), Is.False);
}
// ================================================================
// チャートが必要な検査(--with-chart.PLAN_06 フェーズ 2)
// 仕様: PLAN_06「チャートが必要」の表と合意済みのしきい値.
// 実測の例は .verify/hwtest/run-20261008-154111/hwtest-result.txt(DFK 33UX178.17 次元)から採った
// ================================================================
// ---- 検査の並び・全体の上限 ----
[Test]
public void CheckIds_チャートあり_接続から校正撮影閉じる検査を経て後始末の順() {
Assert.That(HwTestJudge.CheckIds(true),
Is.EqualTo(new[] { "connect", "calibrate", "shot", "close-saving", "close-calibrating", "cleanup" }));
}
[Test]
public void CheckIds_チャートなし_従来のチャート不要の検査の順() {
Assert.That(HwTestJudge.CheckIds(false),
Is.EqualTo(new[] { "connect", "preview", "exposure-gain", "light", "close-preview", "reconnect", "cleanup" }));
}
[Test]
public void CheckIds_チャートあり_チャート不要の検査を含まない() {
Assert.That(HwTestJudge.CheckIds(true), Has.None.AnyOf("preview", "exposure-gain", "light", "close-preview", "reconnect"));
}
[Test]
public void OverallTimeout_チャートなし_600秒() {
Assert.That(HwTestJudge.OverallTimeout(false), Is.EqualTo(TimeSpan.FromSeconds(600)));
}
[Test]
public void OverallTimeout_チャートあり_1200秒() {
Assert.That(HwTestJudge.OverallTimeout(true), Is.EqualTo(TimeSpan.FromSeconds(1200)));
}
[Test]
public void OverallTimeout_チャートあり_チャートありの項目の上限の合計より長い() {
var sum = HwTestThresholds.ConnectTimeout + HwTestThresholds.CalibrateTimeout + HwTestThresholds.ShotTimeout
+ HwTestThresholds.CloseSavingTimeout + HwTestThresholds.CloseCalibratingTimeout + HwTestThresholds.CleanupTimeout;
Assert.That(HwTestJudge.OverallTimeout(true), Is.GreaterThan(sum));
}
// ---- 合意済みのしきい値 ----
[Test]
public void Thresholds_校正の待ち時間_60秒() {
Assert.That(HwTestThresholds.CalibrationWait, Is.EqualTo(TimeSpan.FromSeconds(60)));
}
[Test]
public void Thresholds_色の誤差の平均の上限_5() {
Assert.That(HwTestThresholds.MaxCalibrationMeanError, Is.EqualTo(5.0));
}
[Test]
public void Thresholds_白色票を除いた最大の上限_10() {
Assert.That(HwTestThresholds.MaxCalibrationMaxError, Is.EqualTo(10.0));
}
[Test]
public void Thresholds_白色票の最大の上限_40() {
Assert.That(HwTestThresholds.MaxCalibrationWhiteMaxError, Is.EqualTo(40.0));
}
[Test]
public void Thresholds_撮影間隔のずれの許容_100ms() {
Assert.That(HwTestThresholds.ShotIntervalToleranceMs, Is.EqualTo(100.0));
}
[Test]
public void Thresholds_保存の待ち_180秒() {
Assert.That(HwTestThresholds.SaveWait, Is.EqualTo(TimeSpan.FromSeconds(180)));
}
[Test]
public void Thresholds_校正中になるまでの待ち_60秒() {
Assert.That(HwTestThresholds.CalibratingWait, Is.EqualTo(TimeSpan.FromSeconds(60)));
}
[Test]
public void Thresholds_閉じる処理の上限_1000ms() {
Assert.That(HwTestThresholds.CloseLimit, Is.EqualTo(TimeSpan.FromMilliseconds(1000)));
}
[Test]
public void Thresholds_閉じた後のフレームの上限_2() {
Assert.That(HwTestThresholds.MaxFramesAfterClose, Is.EqualTo(2));
}
// ---- 時刻の差 ----
[Test]
public void TimestampDeltaMs_周波数で割ってミリ秒にする() {
Assert.That(HwTestJudge.TimestampDeltaMs(1000, 3500, 1000), Is.EqualTo(2500.0).Within(Eps));
}
[Test]
public void TimestampDeltaMs_高分解能の周波数_ミリ秒に換算する() {
// Stopwatch.Frequency の典型値 10 MHz で 1 秒の差
Assert.That(HwTestJudge.TimestampDeltaMs(5000000, 15000000, 10000000), Is.EqualTo(1000.0).Within(Eps));
}
[Test]
public void TimestampDeltaMs_同じ時刻_0() {
Assert.That(HwTestJudge.TimestampDeltaMs(1234, 1234, 1000), Is.EqualTo(0.0).Within(Eps));
}
[Test]
public void TimestampDeltaMs_開始が未記録の0_NaN() {
Assert.That(HwTestJudge.TimestampDeltaMs(0, 1000, 1000), Is.NaN);
}
[Test]
public void TimestampDeltaMs_終了が未記録の0_NaN() {
Assert.That(HwTestJudge.TimestampDeltaMs(1000, 0, 1000), Is.NaN);
}
[Test]
public void TimestampDeltaMs_逆順_NaN() {
Assert.That(HwTestJudge.TimestampDeltaMs(2000, 1000, 1000), Is.NaN);
}
[TestCase(0L)]
[TestCase(-1000L)]
public void TimestampDeltaMs_周波数が0以下_NaN(long frequency) {
Assert.That(HwTestJudge.TimestampDeltaMs(1000, 2000, frequency), Is.NaN);
}
// ---- 色の誤差の判定 ----
private static bool JudgeColor(double meanAbs, double otherMax, double whiteMax) {
return HwTestJudge.JudgeColorError(meanAbs, otherMax, whiteMax,
HwTestThresholds.MaxCalibrationMeanError, HwTestThresholds.MaxCalibrationMaxError, HwTestThresholds.MaxCalibrationWhiteMaxError);
}
[Test]
public void JudgeColorError_実測の値_合格() {
// 2026-10-08 15:41 の実測(17 次元): 平均 1.57・白色票を除いた最大 3.47・白色票 24.65
Assert.That(JudgeColor(1.57, 3.47, 24.65), Is.True);
}
[Test]
public void JudgeColorError_すべて上限ちょうど_合格() {
Assert.That(JudgeColor(5.0, 10.0, 40.0), Is.True);
}
[Test]
public void JudgeColorError_平均が上限超え_不合格() {
Assert.That(JudgeColor(5.01, 3.47, 24.65), Is.False);
}
[Test]
public void JudgeColorError_白色票を除いた最大が上限超え_不合格() {
Assert.That(JudgeColor(1.57, 10.01, 24.65), Is.False);
}
[Test]
public void JudgeColorError_白色票の最大が上限超え_不合格() {
Assert.That(JudgeColor(1.57, 3.47, 40.01), Is.False);
}
[Test]
public void JudgeColorError_白色票の誤差は白色票の上限で見る_白色票以外の上限を超えても合格() {
// 白色票の 30 は白色票以外の上限 10 を超えるが,白色票の上限 40 以内なので合格
Assert.That(JudgeColor(1.57, 3.47, 30.0), Is.True);
}
[TestCase(double.NaN, 3.47, 24.65)]
[TestCase(1.57, double.NaN, 24.65)]
[TestCase(1.57, 3.47, double.NaN)]
public void JudgeColorError_いずれかがNaN_不合格(double meanAbs, double otherMax, double whiteMax) {
Assert.That(JudgeColor(meanAbs, otherMax, whiteMax), Is.False);
}
[Test]
public void JudgeColorError_上限を引数で受け取る_引数の上限で判定する() {
Assert.That(HwTestJudge.JudgeColorError(2.0, 2.0, 2.0, 1.0, 100.0, 100.0), Is.False);
}
// ---- 撮影ログ(Info.csv)の読み取り ----
[Test]
public void ParseShotLog_連続撮影のログ_番号と時刻を読む() {
var lines = new[] { "Shot,Time(ms),Note", "1,0", "2,1002", "3,2006" };
var rows = HwTestJudge.ParseShotLog(lines, out _);
Assert.That(rows.ConvertAll(r => r.TimeMs), Is.EqualTo(new[] { 0L, 1002L, 2006L }));
}
[Test]
public void ParseShotLog_連続撮影のログ_番号を読む() {
var lines = new[] { "Shot,Time(ms),Note", "1,0", "2,1002", "3,2006" };
var rows = HwTestJudge.ParseShotLog(lines, out _);
Assert.That(rows.ConvertAll(r => r.Shot), Is.EqualTo(new[] { 1, 2, 3 }));
}
[Test]
public void ParseShotLog_正常なログ_errorはnull() {
var lines = new[] { "Shot,Time(ms),Note", "1,0" };
HwTestJudge.ParseShotLog(lines, out var error);
Assert.That(error, Is.Null);
}
[Test]
public void ParseShotLog_備考なし_備考は空() {
var rows = HwTestJudge.ParseShotLog(new[] { "Shot,Time(ms),Note", "1,0" }, out _);
Assert.That(rows[0].Note, Is.EqualTo(""));
}
[Test]
public void ParseShotLog_見出しより前の行_読み飛ばす() {
var lines = new[] { "Name,hwtest-shot-multi", "Date,2026-10-08", "Shot,Time(ms),Note", "1,0", "2,1002" };
var rows = HwTestJudge.ParseShotLog(lines, out var error);
Assert.That(rows.Count, Is.EqualTo(2));
}
[Test]
public void ParseShotLog_空行_読み飛ばす() {
var lines = new[] { "Shot,Time(ms),Note", "1,0", "", "2,1002", "" };
var rows = HwTestJudge.ParseShotLog(lines, out var error);
Assert.That(rows.Count, Is.EqualTo(2));
}
[Test]
public void ParseShotLog_カンマを含むエスケープした備考_エスケープのまま残す() {
var note = "\"撮影失敗のため中止(a,b \"\"x\"\")\"";
var rows = HwTestJudge.ParseShotLog(new[] { "Shot,Time(ms),Note", "1,0", "2,1002," + note }, out _);
Assert.That(rows[1].Note, Is.EqualTo(note));
}
[Test]
public void ParseShotLog_見出し行が無い_errorを返す() {
HwTestJudge.ParseShotLog(new[] { "1,0", "2,1002" }, out var error);
Assert.That(error, Is.Not.Null);
}
[Test]
public void ParseShotLog_見出し行が無い_行を返さない() {
var rows = HwTestJudge.ParseShotLog(new[] { "1,0", "2,1002" }, out _);
Assert.That(rows, Is.Empty);
}
[Test]
public void ParseShotLog_時刻が数値でない行_errorを返す() {
HwTestJudge.ParseShotLog(new[] { "Shot,Time(ms),Note", "1,0", "2,abc" }, out var error);
Assert.That(error, Is.Not.Null);
}
[Test]
public void ParseShotLog_番号が数値でない行_errorを返す() {
HwTestJudge.ParseShotLog(new[] { "Shot,Time(ms),Note", "x,0" }, out var error);
Assert.That(error, Is.Not.Null);
}
[Test]
public void ParseShotLog_列が足りない行_errorを返す() {
HwTestJudge.ParseShotLog(new[] { "Shot,Time(ms),Note", "1" }, out var error);
Assert.That(error, Is.Not.Null);
}
[Test]
public void ParseShotLog_途中で読めない行_それまでの行を返す() {
var rows = HwTestJudge.ParseShotLog(new[] { "Shot,Time(ms),Note", "1,0", "2,abc", "3,2006" }, out _);
Assert.That(rows.Count, Is.EqualTo(1));
}
[Test]
public void ParseShotLog_null_errorを返す() {
HwTestJudge.ParseShotLog(null, out var error);
Assert.That(error, Is.Not.Null);
}
// ---- 撮影間隔のずれ ----
[Test]
public void MaxIntervalDeviationMs_実測の撮影時刻_最大のずれ() {
// 0/1002/2006: 間隔 1002・1004 → 設定 1000 との差 2・4 の最大 4
Assert.That(HwTestJudge.MaxIntervalDeviationMs(new long[] { 0, 1002, 2006 }, 1000), Is.EqualTo(4.0).Within(Eps));
}
[Test]
public void MaxIntervalDeviationMs_間隔が設定より短い_差の絶対値() {
Assert.That(HwTestJudge.MaxIntervalDeviationMs(new long[] { 0, 900, 1900 }, 1000), Is.EqualTo(100.0).Within(Eps));
}
[Test]
public void MaxIntervalDeviationMs_間隔0の連続撮影_間隔そのものがずれ() {
Assert.That(HwTestJudge.MaxIntervalDeviationMs(new long[] { 0, 40, 73, 107, 138 }, 0), Is.EqualTo(40.0).Within(Eps));
}
[Test]
public void MaxIntervalDeviationMs_設定どおり_0() {
Assert.That(HwTestJudge.MaxIntervalDeviationMs(new long[] { 0, 1000, 2000 }, 1000), Is.EqualTo(0.0).Within(Eps));
}
[Test]
public void MaxIntervalDeviationMs_1件_NaN() {
Assert.That(HwTestJudge.MaxIntervalDeviationMs(new long[] { 0 }, 1000), Is.NaN);
}
[Test]
public void MaxIntervalDeviationMs_0件_NaN() {
Assert.That(HwTestJudge.MaxIntervalDeviationMs(new long[0], 1000), Is.NaN);
}
[Test]
public void MaxIntervalDeviationMs_null_NaN() {
Assert.That(HwTestJudge.MaxIntervalDeviationMs(null, 1000), Is.NaN);
}
// ---- 保存されるファイル名 ----
[Test]
public void ExpectedShotFiles_単発撮影で1次元_InfoとShotとsRGBの3件() {
var names = HwTestJudge.ExpectedShotFiles("Shot{NO}.png", "sRGB{CN}_{NO}.jpg", "Info.csv", new[] { 17 }, 1);
Assert.That(names, Is.EquivalentTo(new[] { "Info.csv", "Shot0001.png", "sRGB17_0001.jpg" }));
}
[Test]
public void ExpectedShotFiles_連続3枚で1次元_7件() {
var names = HwTestJudge.ExpectedShotFiles("Shot{NO}.png", "sRGB{CN}_{NO}.jpg", "Info.csv", new[] { 17 }, 3);
Assert.That(names.Count, Is.EqualTo(7));
}
[Test]
public void ExpectedShotFiles_番号は4桁の1始まり() {
var names = HwTestJudge.ExpectedShotFiles("Shot{NO}.png", "sRGB{CN}_{NO}.jpg", "Info.csv", new int[0], 3);
Assert.That(names, Is.EquivalentTo(new[] { "Info.csv", "Shot0001.png", "Shot0002.png", "Shot0003.png" }));
}
[Test]
public void ExpectedShotFiles_項目数は2桁() {
var names = HwTestJudge.ExpectedShotFiles("Shot{NO}.png", "sRGB{CN}_{NO}.jpg", "Info.csv", new[] { 4, 17 }, 1);
Assert.That(names, Is.EquivalentTo(new[] { "Info.csv", "Shot0001.png", "sRGB04_0001.jpg", "sRGB17_0001.jpg" }));
}
[Test]
public void ExpectedShotFiles_項目数がnull_sRGB変換画像なし() {
var names = HwTestJudge.ExpectedShotFiles("Shot{NO}.png", "sRGB{CN}_{NO}.jpg", "Info.csv", null, 2);
Assert.That(names, Is.EquivalentTo(new[] { "Info.csv", "Shot0001.png", "Shot0002.png" }));
}
[Test]
public void ExpectedShotFiles_枚数0_Infoだけ() {
var names = HwTestJudge.ExpectedShotFiles("Shot{NO}.png", "sRGB{CN}_{NO}.jpg", "Info.csv", new[] { 17 }, 0);
Assert.That(names, Is.EquivalentTo(new[] { "Info.csv" }));
}
[Test]
public void ExpectedShotFiles_書式がnull_ArgumentNullException() {
Assert.Throws<ArgumentNullException>((Action)(() =>
HwTestJudge.ExpectedShotFiles(null, "sRGB{CN}_{NO}.jpg", "Info.csv", new[] { 17 }, 1)));
}
[Test]
public void CompareFileNames_一致_足りないものも余分なものも無い() {
HwTestJudge.CompareFileNames(new[] { "Info.csv", "Shot0001.png" }, new[] { "Shot0001.png", "Info.csv" },
out var missing, out var unexpected);
Assert.That(missing.Count + unexpected.Count, Is.EqualTo(0));
}
[Test]
public void CompareFileNames_大文字小文字の違い_一致とみなす() {
HwTestJudge.CompareFileNames(new[] { "Info.csv", "Shot0001.png" }, new[] { "INFO.CSV", "shot0001.PNG" },
out var missing, out var unexpected);
Assert.That(missing.Count + unexpected.Count, Is.EqualTo(0));
}
[Test]
public void CompareFileNames_足りないファイル_missingに入る() {
HwTestJudge.CompareFileNames(new[] { "Info.csv", "Shot0001.png", "sRGB17_0001.jpg" }, new[] { "Info.csv" },
out var missing, out _);
Assert.That(missing, Is.EqualTo(new[] { "Shot0001.png", "sRGB17_0001.jpg" }));
}
[Test]
public void CompareFileNames_余分なファイル_unexpectedに入る() {
HwTestJudge.CompareFileNames(new[] { "Info.csv" }, new[] { "Info.csv", "Shot0002.png" },
out _, out var unexpected);
Assert.That(unexpected, Is.EqualTo(new[] { "Shot0002.png" }));
}
[Test]
public void CompareFileNames_結果は名前順() {
HwTestJudge.CompareFileNames(new[] { "c.png", "a.png", "B.png" }, new string[0], out var missing, out _);
Assert.That(missing, Is.EqualTo(new[] { "a.png", "B.png", "c.png" }));
}
// ---- 保存中に閉じる検査 ----
[Test]
public void DecideSavingAttempt_保存中を観測_Ready() {
Assert.That(HwTestJudge.DecideSavingAttempt(true, 1, HwTestThresholds.CloseSavingMaxAttempts), Is.EqualTo(HwTestSavingAttempt.Ready));
}
[Test]
public void DecideSavingAttempt_最後の試行で保存中を観測_Ready() {
Assert.That(HwTestJudge.DecideSavingAttempt(true, 2, 2), Is.EqualTo(HwTestSavingAttempt.Ready));
}
[Test]
public void DecideSavingAttempt_1回目で保存中にならない_Retry() {
Assert.That(HwTestJudge.DecideSavingAttempt(false, 1, 2), Is.EqualTo(HwTestSavingAttempt.Retry));
}
[Test]
public void DecideSavingAttempt_上限の回で保存中にならない_GiveUp() {
Assert.That(HwTestJudge.DecideSavingAttempt(false, 2, 2), Is.EqualTo(HwTestSavingAttempt.GiveUp));
}
[Test]
public void Thresholds_保存中を作る試行_最初と再試行1回の2回() {
Assert.That(HwTestThresholds.CloseSavingMaxAttempts, Is.EqualTo(2));
}
[Test]
public void CloseSavingShotCount_1回目_5枚() {
Assert.That(HwTestJudge.CloseSavingShotCount(1), Is.EqualTo(5));
}
[TestCase(2)]
[TestCase(3)]
public void CloseSavingShotCount_2回目以降_10枚(int attempt) {
Assert.That(HwTestJudge.CloseSavingShotCount(attempt), Is.EqualTo(10));
}
private const string SavingMsg = "保存中です.保存完了後に閉じてください";
[Test]
public void CancelledCloseProblems_正しく取り消された_問題なし() {
Assert.That(HwTestJudge.CancelledCloseProblems(false, SavingMsg, SavingMsg, 0, false, true), Is.Empty);
}
[Test]
public void CancelledCloseProblems_閉じると決まった_問題あり() {
Assert.That(HwTestJudge.CancelledCloseProblems(true, SavingMsg, SavingMsg, 0, false, true).Count, Is.EqualTo(1));
}
[Test]
public void CancelledCloseProblems_表示が違う_問題に表示を含める() {
var problems = HwTestJudge.CancelledCloseProblems(false, "全ての画像保存完了", SavingMsg, 0, false, true);
Assert.That(problems, Has.Exactly(1).Contains("全ての画像保存完了"));
}
[Test]
public void CancelledCloseProblems_表示がnull_問題あり() {
Assert.That(HwTestJudge.CancelledCloseProblems(false, null, SavingMsg, 0, false, true).Count, Is.EqualTo(1));
}
[Test]
public void CancelledCloseProblems_後始末が進んだ_問題あり() {
Assert.That(HwTestJudge.CancelledCloseProblems(false, SavingMsg, SavingMsg, 1, false, true).Count, Is.EqualTo(1));
}
[Test]
public void CancelledCloseProblems_閉じ始めのフラグが立った_問題あり() {
Assert.That(HwTestJudge.CancelledCloseProblems(false, SavingMsg, SavingMsg, 0, true, true).Count, Is.EqualTo(1));
}
[Test]
public void CancelledCloseProblems_再描画タイマーが止まった_問題あり() {
Assert.That(HwTestJudge.CancelledCloseProblems(false, SavingMsg, SavingMsg, 0, false, false).Count, Is.EqualTo(1));
}
[Test]
public void CancelledCloseProblems_すべて異常_5件() {
Assert.That(HwTestJudge.CancelledCloseProblems(true, "x", SavingMsg, 4, true, false).Count, Is.EqualTo(5));
}
// ---- 後始末の順序 ----
[Test]
public void IsCloseSequenceSince_開始位置から正しい順_true() {
var steps = new[] { "closing", "timer", "camera", "light", "closing", "timer", "camera", "light" };
Assert.That(HwTestJudge.IsCloseSequenceSince(steps, 4), Is.True);
}
[Test]
public void IsCloseSequenceSince_開始位置0から正しい順_true() {
Assert.That(HwTestJudge.IsCloseSequenceSince(new[] { "closing", "timer", "camera", "light" }, 0), Is.True);
}
[Test]
public void IsCloseSequenceSince_順序が違う_false() {
Assert.That(HwTestJudge.IsCloseSequenceSince(new[] { "closing", "camera", "timer", "light" }, 0), Is.False);
}
[Test]
public void IsCloseSequenceSince_段階が足りない_false() {
Assert.That(HwTestJudge.IsCloseSequenceSince(new[] { "closing", "timer", "camera" }, 0), Is.False);
}
[Test]
public void IsCloseSequenceSince_余分な段階がある_false() {
Assert.That(HwTestJudge.IsCloseSequenceSince(new[] { "closing", "timer", "camera", "light", "light" }, 0), Is.False);
}
[Test]
public void IsCloseSequenceSince_何も進んでいない_false() {
Assert.That(HwTestJudge.IsCloseSequenceSince(new[] { "closing", "timer", "camera", "light" }, 4), Is.False);
}
[TestCase(-1)]
[TestCase(5)]
public void IsCloseSequenceSince_開始位置が範囲外_false(int start) {
Assert.That(HwTestJudge.IsCloseSequenceSince(new[] { "closing", "timer", "camera", "light" }, start), Is.False);
}
[Test]
public void IsCloseSequenceSince_null_false() {
Assert.That(HwTestJudge.IsCloseSequenceSince(null, 0), Is.False);
}
[Test]
public void StepsSince_開始位置以降を返す() {
Assert.That(HwTestJudge.StepsSince(new[] { "closing", "timer", "closing", "timer" }, 2), Is.EqualTo(new[] { "closing", "timer" }));
}
[Test]
public void StepsSince_開始位置が末尾_空() {
Assert.That(HwTestJudge.StepsSince(new[] { "closing" }, 1), Is.Empty);
}
[Test]
public void StepsSince_開始位置が負_全部() {
Assert.That(HwTestJudge.StepsSince(new[] { "closing", "timer" }, -1), Is.EqualTo(new[] { "closing", "timer" }));
}
[Test]
public void StepsSince_null_空() {
Assert.That(HwTestJudge.StepsSince(null, 0), Is.Empty);
}
// ---- 色票内の画素の集計(白飛び・黒つぶれ) ----
[Test]
public void SummarizePatchPixels_画素の数() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 1, 2, 3, 4, 5, 6 });
Assert.That(s.Pixels, Is.EqualTo(2));
}
[Test]
public void SummarizePatchPixels_チャネルごとの平均_BGRの順() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 10, 20, 30, 30, 40, 50 });
Assert.That(s.Mean, Is.EqualTo(new[] { 20.0, 30.0, 40.0 }).Within(Eps));
}
[Test]
public void SummarizePatchPixels_チャネルごとの最小() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 10, 60, 30, 30, 40, 50 });
Assert.That(s.Min, Is.EqualTo(new[] { 10.0, 40.0, 30.0 }).Within(Eps));
}
[Test]
public void SummarizePatchPixels_チャネルごとの最大() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 10, 60, 30, 30, 40, 50 });
Assert.That(s.Max, Is.EqualTo(new[] { 30.0, 60.0, 50.0 }).Within(Eps));
}
[Test]
public void SummarizePatchPixels_255の画素_白飛びの割合に数える() {
// 4 画素のうち 1 画素が G=255(8bit の頭打ち)
var s = HwTestJudge.SummarizePatchPixels(new double[] { 100, 255, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 });
Assert.That(s.FractionAnyAtOrAboveMax, Is.EqualTo(0.25).Within(Eps));
}
[Test]
public void SummarizePatchPixels_255ちょうど_超えた割合には数えない() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 255, 255, 255 });
Assert.That(s.FractionAnyAboveMax, Is.EqualTo(0.0).Within(Eps));
}
[Test]
public void SummarizePatchPixels_255を超えた画素_超えた割合に数える() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 621.4, 200, 200, 100, 100, 100 });
Assert.That(s.FractionAnyAboveMax, Is.EqualTo(0.5).Within(Eps));
}
[Test]
public void SummarizePatchPixels_255を超えた画素_以上の割合にも数える() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 621.4, 200, 200, 100, 100, 100 });
Assert.That(s.FractionAnyAtOrAboveMax, Is.EqualTo(0.5).Within(Eps));
}
[Test]
public void SummarizePatchPixels_0の画素_黒つぶれの割合に数える() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 0, 2, 0, 100, 100, 100 });
Assert.That(s.FractionAnyAtOrBelowMin, Is.EqualTo(0.5).Within(Eps));
}
[Test]
public void SummarizePatchPixels_0ちょうど_0未満の割合には数えない() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 0, 0, 0 });
Assert.That(s.FractionAnyBelowMin, Is.EqualTo(0.0).Within(Eps));
}
[Test]
public void SummarizePatchPixels_0未満の画素_0未満の割合と以下の割合に数える() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { -175.6, 2, -42.3, 100, 100, 100 });
Assert.That(new[] { s.FractionAnyBelowMin, s.FractionAnyAtOrBelowMin }, Is.EqualTo(new[] { 0.5, 0.5 }).Within(Eps));
}
[Test]
public void SummarizePatchPixels_1画素で複数チャネルが255_1画素として数える() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 255, 255, 255, 100, 100, 100 });
Assert.That(s.FractionAnyAtOrAboveMax, Is.EqualTo(0.5).Within(Eps));
}
[Test]
public void SummarizePatchPixels_範囲内の画素だけ_割合はすべて0() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { 1, 128, 254, 100, 100, 100 });
Assert.That(new[] { s.FractionAnyAtOrAboveMax, s.FractionAnyAtOrBelowMin, s.FractionAnyAboveMax, s.FractionAnyBelowMin },
Is.EqualTo(new[] { 0.0, 0.0, 0.0, 0.0 }));
}
[Test]
public void SummarizePatchPixels_空_画素数0() {
var s = HwTestJudge.SummarizePatchPixels(new double[0]);
Assert.That(s.Pixels, Is.EqualTo(0));
}
[Test]
public void SummarizePatchPixels_空_平均最小最大はNaN() {
var s = HwTestJudge.SummarizePatchPixels(new double[0]);
Assert.That(new[] { s.Mean[0], s.Mean[1], s.Mean[2], s.Min[0], s.Min[1], s.Min[2], s.Max[0], s.Max[1], s.Max[2] }, Has.All.NaN);
}
[Test]
public void SummarizePatchPixels_空_割合4種はNaN() {
var s = HwTestJudge.SummarizePatchPixels(new double[0]);
Assert.That(new[] { s.FractionAnyAtOrAboveMax, s.FractionAnyAtOrBelowMin, s.FractionAnyAboveMax, s.FractionAnyBelowMin }, Has.All.NaN);
}
[TestCase(1)]
[TestCase(2)]
[TestCase(4)]
public void SummarizePatchPixels_長さが3の倍数でない_ArgumentException(int length) {
Assert.Throws<ArgumentException>((Action)(() => HwTestJudge.SummarizePatchPixels(new double[length])));
}
[Test]
public void SummarizePatchPixels_null_ArgumentNullException() {
Assert.Throws<ArgumentNullException>((Action)(() => HwTestJudge.SummarizePatchPixels(null)));
}
[Test]
public void SummarizePatchPixels_NaNの画素_そのチャネルの平均はNaN() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { double.NaN, 10, 10, 20, 20, 20 });
Assert.That(s.Mean[0], Is.NaN);
}
[Test]
public void SummarizePatchPixels_NaNの画素_他のチャネルの平均は影響しない() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { double.NaN, 10, 10, 20, 20, 20 });
Assert.That(new[] { s.Mean[1], s.Mean[2] }, Is.EqualTo(new[] { 15.0, 15.0 }).Within(Eps));
}
[Test]
public void SummarizePatchPixels_NaNの画素_最小最大に数えない() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { double.NaN, 10, 10, 20, 20, 20 });
Assert.That(new[] { s.Min[0], s.Max[0] }, Is.EqualTo(new[] { 20.0, 20.0 }).Within(Eps));
}
[Test]
public void SummarizePatchPixels_NaNの画素_割合に数えない() {
var s = HwTestJudge.SummarizePatchPixels(new double[] { double.NaN, double.NaN, double.NaN, 100, 100, 100 });
Assert.That(new[] { s.FractionAnyAtOrAboveMax, s.FractionAnyAtOrBelowMin, s.FractionAnyAboveMax, s.FractionAnyBelowMin },
Is.EqualTo(new[] { 0.0, 0.0, 0.0, 0.0 }));
}
}
}
#endif