#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