Newer
Older
TIASShot / TIASshot.Tests / ConfigTests.cs
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.AreEqual(ExpectedFloat, value, 1e-6f);
        }

        /// <summary>
        /// GetInt で整数値が正しく取得できる
        /// </summary>
        [Test]
        public void GetInt_存在するキー_正しい値を返す() {
            var value = Config.GetInt("IntVal");
            Assert.AreEqual(ExpectedInt, value);
        }

        /// <summary>
        /// GetString で文字列値が正しく取得できる
        /// </summary>
        [Test]
        public void GetString_存在するキー_正しい値を返す() {
            var value = Config.GetString("StrVal");
            Assert.AreEqual(ExpectedString, value);
        }

        /// <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.AreEqual(ExpectedNested, value);
        }

        /// <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.AreEqual(ExpectedFloat, value, 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.IsTrue(File.Exists(repoConfigPath), $"同梱 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.AreNotEqual(0, Config.GetInt("Calib/UpdateInterval"));
            Assert.AreNotEqual(0.0f, Config.GetFloat("Calib/UpdateRate"));
        }
    }
}