using System;
using System.IO;
using NUnit.Framework;
namespace TIASshot.Tests {
/// <summary>
/// Config のテスト(XML パース・型変換・存在しないキーの例外)
/// </summary>
[TestFixture]
public class ConfigTests {
private string _tempConfigPath;
// テスト用 XML の期待値定数
private const float ExpectedFloat = 1.5f;
private const int ExpectedInt = 42;
private const string ExpectedString = "hello";
private const string ExpectedNested = "deep";
private const string TestConfigXml =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<Config>" +
" <FloatVal>1.5</FloatVal>" +
" <IntVal>42</IntVal>" +
" <StrVal>hello</StrVal>" +
" <Nested><Child>deep</Child></Nested>" +
" <BadNumVal>abc</BadNumVal>" +
" <EmptyVal></EmptyVal>" +
"</Config>";
[SetUp]
public void SetUp() {
_tempConfigPath = Path.GetTempFileName();
// 拡張子を .xml に変更(XmlDocument.Load は拡張子を問わないが明示するために rename)
var xmlPath = _tempConfigPath + ".xml";
File.Move(_tempConfigPath, xmlPath);
_tempConfigPath = xmlPath;
File.WriteAllText(_tempConfigPath, TestConfigXml, System.Text.Encoding.UTF8);
Config.Load(_tempConfigPath);
}
[TearDown]
public void TearDown() {
if (File.Exists(_tempConfigPath)) File.Delete(_tempConfigPath);
}
/// <summary>
/// GetFloat でフロート値が正しく取得できる
/// </summary>
[Test]
public void GetFloat_存在するキー_正しい値を返す() {
var value = Config.GetFloat("FloatVal");
Assert.That(value, Is.EqualTo(ExpectedFloat).Within(1e-6f));
}
/// <summary>
/// GetInt で整数値が正しく取得できる
/// </summary>
[Test]
public void GetInt_存在するキー_正しい値を返す() {
var value = Config.GetInt("IntVal");
Assert.That(value, Is.EqualTo(ExpectedInt));
}
/// <summary>
/// GetString で文字列値が正しく取得できる
/// </summary>
[Test]
public void GetString_存在するキー_正しい値を返す() {
var value = Config.GetString("StrVal");
Assert.That(value, Is.EqualTo(ExpectedString));
}
/// <summary>
/// 存在しないキーを指定したとき ArgumentException がスローされる
/// </summary>
[Test]
public void GetFloat_存在しないキー_ArgumentExceptionをスロー() {
Assert.Throws<ArgumentException>(() => Config.GetFloat("NoSuchKey"));
}
/// <summary>
/// 存在しないキーを GetInt で指定したとき ArgumentException がスローされる
/// </summary>
[Test]
public void GetInt_存在しないキー_ArgumentExceptionをスロー() {
Assert.Throws<ArgumentException>(() => Config.GetInt("NoSuchKey"));
}
/// <summary>
/// 存在しないキーを GetString で指定したとき ArgumentException がスローされる
/// </summary>
[Test]
public void GetString_存在しないキー_ArgumentExceptionをスロー() {
Assert.Throws<ArgumentException>(() => Config.GetString("NoSuchKey"));
}
/// <summary>
/// ネストした要素(Nested/Child)を XPath スラッシュ区切りで取得できる
/// </summary>
[Test]
public void GetString_ネスト要素_正しい値を返す() {
var value = Config.GetString("Nested/Child");
Assert.That(value, Is.EqualTo(ExpectedNested));
}
/// <summary>
/// 数値としてパースできない値を GetInt で指定したとき ArgumentException がスローされる
/// (キー欠落時と同様に設定不備として扱う.黙って 0 を返さない)
/// </summary>
[Test]
public void GetInt_数値でない値_ArgumentExceptionをスロー() {
Assert.Throws<ArgumentException>(() => Config.GetInt("BadNumVal"));
}
/// <summary>
/// 数値としてパースできない値を GetFloat で指定したとき ArgumentException がスローされる
/// </summary>
[Test]
public void GetFloat_数値でない値_ArgumentExceptionをスロー() {
Assert.Throws<ArgumentException>(() => Config.GetFloat("BadNumVal"));
}
/// <summary>
/// 空要素を GetInt で指定したとき ArgumentException がスローされる
/// </summary>
[Test]
public void GetInt_空の値_ArgumentExceptionをスロー() {
Assert.Throws<ArgumentException>(() => Config.GetInt("EmptyVal"));
}
/// <summary>
/// 小数点にカンマを使うロケール(de-DE)でもピリオド小数の設定値を正しく解釈する
/// (config.xml はピリオド小数で記述される仕様のため,パースはロケール非依存であること)
/// </summary>
[Test]
public void GetFloat_カンマ小数ロケール_ピリオド小数を正しく解釈する() {
var original = System.Threading.Thread.CurrentThread.CurrentCulture;
try {
System.Threading.Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo("de-DE");
var value = Config.GetFloat("FloatVal");
Assert.That(value, Is.EqualTo(ExpectedFloat).Within(1e-6f));
} finally {
System.Threading.Thread.CurrentThread.CurrentCulture = original;
}
}
/// <summary>
/// 特性化テスト: リポジトリ同梱の config.xml に対して,本体コードが参照する
/// 全数値キーが例外なく読めること(不正値 throw 化で正常系が変わらない保護)
/// </summary>
[Test]
public void GetIntGetFloat_同梱config_本体が参照する全数値キーを例外なく読める() {
var repoConfigPath = Path.GetFullPath(Path.Combine(
TestContext.CurrentContext.TestDirectory,
"..", "..", "..", "..", "TIASshot", "config.xml"));
Assert.That(File.Exists(repoConfigPath), Is.True, $"同梱 config.xml が見つからない: {repoConfigPath}");
Config.Load(repoConfigPath);
string[] intKeys = {
"Calib/ChartSetCount", "Calib/Frames", "Calib/UpdateInterval",
"Shot/PreviewMonitorWidth", "LightSource/BaudRate",
"DFK33UX178/ROI/X", "DFK33UX178/ROI/Y", "DFK33UX178/ROI/W", "DFK33UX178/ROI/H",
"DFK23UX249/ROI/X", "DFK23UX249/ROI/Y", "DFK23UX249/ROI/W", "DFK23UX249/ROI/H",
};
string[] floatKeys = {
"Lucam/Exposure", "Lucam/Gain", "Lucam/GainB", "Lucam/GainG", "Lucam/GainR",
"Calib/ChartSetCriteria", "Calib/UpdateRate",
"Calib/Reference/B", "Calib/Reference/G", "Calib/Reference/R",
};
foreach (var key in intKeys) {
Assert.DoesNotThrow(() => Config.GetInt(key), $"GetInt(\"{key}\") が例外を投げた");
}
foreach (var key in floatKeys) {
Assert.DoesNotThrow(() => Config.GetFloat(key), $"GetFloat(\"{key}\") が例外を投げた");
}
// ゼロ除算・校正停止に直結する値が有効値で読めることを固定する
Assert.That(Config.GetInt("Calib/UpdateInterval"), Is.Not.EqualTo(0));
Assert.That(Config.GetFloat("Calib/UpdateRate"), Is.Not.EqualTo(0.0f));
}
}
}