Newer
Older
TIASShot / TIASshot / SelfTest / SelfTestConfig.cs
#if SELFTEST
using System.Collections.Generic;
using System.IO;
using System.Xml;

namespace TIASshot {

    /// <summary>
    /// セルフテスト・結合ロジックテスト(層②)用の一時設定ファイルを作る(SELFTEST 限定).
    /// SelfTestRunner と TIASshot.Tests の共通ハーネスの両方から使う.
    /// 同梱 config.xml を複製し,保存先(File/SaveFolder)を作業フォルダ配下に,参照 CSV を基準フォルダの絶対パスに,
    /// 効果音を存在しないパス(再生しない)に差し替えて作業フォルダへ書き出し,Config に読み込む.
    /// 元の config.xml は変更しない.
    /// </summary>
    internal static class SelfTestConfig {

        /// <summary>作業フォルダに書き出す一時設定ファイルの名前</summary>
        public const string FileName = "config.selftest.xml";

        /// <summary>作業フォルダ内の保存先フォルダの名前(File/SaveFolder の差し替え先)</summary>
        public const string SaveFolderName = "data";

        /// <summary>準備した一時設定の情報</summary>
        internal sealed class Prepared {
            /// <summary>書き出した一時設定ファイルのパス</summary>
            public string ConfigPath;
            /// <summary>一時設定の File/SaveFolder(作業フォルダ配下)</summary>
            public string SaveRoot;
            /// <summary>元の config.xml の File/SaveFolder(書き込まないことの確認用)</summary>
            public string UserSaveFolder;
        }

        /// <summary>
        /// 一時設定ファイルを作り,Config.Load で読み込む.
        /// </summary>
        /// <param name="sourceConfig">複製元の config.xml のパス(読むだけ)</param>
        /// <param name="refBaseDir">相対パスで書かれた参照 CSV(File/TccSrgbRef・File/TccXyzRef)の基準フォルダ</param>
        /// <param name="workDir">作業フォルダ(無ければ作る.一時設定と保存先はこの配下に置く)</param>
        /// <param name="overrides">
        /// 上書きする設定(キーは "Calib/Frames" のような Config のパス,値は InnerText).null 可.
        /// 値が null の項目は要素ごと削除する(設定欠落の注入用).標準の差し替えより後に適用する.
        /// 存在しないキーに値を設定しようとした場合は InvalidDataException(キーの打ち間違いの検出).
        /// </param>
        /// <param name="fileName">作業フォルダに書き出す一時設定ファイルの名前.null のときは <see cref="FileName"/>(実機テストは別名にする)</param>
        /// <returns>準備した一時設定の情報</returns>
        /// <exception cref="IOException">ファイル・フォルダの読み書きに失敗した場合</exception>
        /// <exception cref="XmlException">複製元が XML として読めない場合</exception>
        /// <exception cref="InvalidDataException">必要な要素が無い場合</exception>
        public static Prepared Prepare(string sourceConfig, string refBaseDir, string workDir,
                IDictionary<string, string> overrides = null, string fileName = null) {
            Directory.CreateDirectory(workDir);
            var doc = new XmlDocument();
            doc.Load(sourceConfig);

            var result = new Prepared {
                UserSaveFolder = GetNode(doc, "File/SaveFolder").InnerText,
                SaveRoot = Path.Combine(workDir, SaveFolderName),
            };
            GetNode(doc, "File/SaveFolder").InnerText = result.SaveRoot;
            foreach (var key in new[] { "File/TccSrgbRef", "File/TccXyzRef" }) {
                var node = GetNode(doc, key);
                if (!Path.IsPathRooted(node.InnerText)) node.InnerText = Path.Combine(refBaseDir, node.InnerText);
            }
            var sounds = doc.SelectSingleNode("//Config/Sound");
            if (sounds != null) {
                foreach (XmlNode node in sounds.ChildNodes) {
                    if (node.NodeType == XmlNodeType.Element) node.InnerText = Path.Combine(workDir, "selftest-no-sound.wav");
                }
            }

            if (overrides != null) {
                foreach (var kv in overrides) {
                    var node = GetNode(doc, kv.Key);
                    if (kv.Value == null) {
                        node.ParentNode.RemoveChild(node);
                    } else {
                        node.InnerText = kv.Value;
                    }
                }
            }

            result.ConfigPath = Path.Combine(workDir, fileName ?? FileName);
            doc.Save(result.ConfigPath);
            Config.Load(result.ConfigPath);
            return result;
        }

        private static XmlNode GetNode(XmlDocument doc, string path) {
            var node = doc.SelectSingleNode($"//Config/{path}");
            if (node == null) throw new InvalidDataException($"config.xml に {path} がありません");
            return node;
        }
    }
}
#endif