Update Live-streaming code (auto-daily features)
This commit is contained in:
@@ -0,0 +1,503 @@
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from app.bettergi_daily import (
|
||||
DAILY_MODE_COMMISSION,
|
||||
DAILY_MODE_DOMAIN,
|
||||
DAILY_MODE_LEY_LINE,
|
||||
DAILY_MODE_NONE,
|
||||
DailyAutomationError,
|
||||
DomainAliasResolver,
|
||||
apply_json_updates,
|
||||
parse_daily_request,
|
||||
prepare_commission_current_party_update,
|
||||
prepare_daily_run,
|
||||
prepare_edit_party_update,
|
||||
prepare_switch_party_update,
|
||||
resolve_party_members,
|
||||
)
|
||||
|
||||
|
||||
class BetterGIDailyTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp_dir = tempfile.TemporaryDirectory()
|
||||
self.root = Path(self.temp_dir.name)
|
||||
self.alias_path = self.root / "domain_aliases.json"
|
||||
self._write_json(
|
||||
self.alias_path,
|
||||
{
|
||||
"_说明": "test",
|
||||
"铭记之谷": ["风本", "少女套"],
|
||||
},
|
||||
)
|
||||
self._write_json(
|
||||
self.root / "User" / "OneDragon" / "默认配置.json",
|
||||
{
|
||||
"Name": "默认配置",
|
||||
"TaskEnabledList": {
|
||||
"mail-template-id": True,
|
||||
"serenitea-template-id": True,
|
||||
"craft-template-id": True,
|
||||
"domain-template-id": False,
|
||||
"ley-line-template-id": False,
|
||||
"daily-reward-template-id": True,
|
||||
},
|
||||
"TaskOrder": [
|
||||
"mail-template-id",
|
||||
"serenitea-template-id",
|
||||
"craft-template-id",
|
||||
"domain-template-id",
|
||||
"ley-line-template-id",
|
||||
"daily-reward-template-id",
|
||||
],
|
||||
"TaskDefinitions": {
|
||||
"mail-template-id": "领取邮件",
|
||||
"serenitea-template-id": "领取尘歌壶奖励",
|
||||
"craft-template-id": "合成树脂",
|
||||
"domain-template-id": "自动秘境",
|
||||
"ley-line-template-id": "自动地脉花",
|
||||
"daily-reward-template-id": "领取每日奖励",
|
||||
},
|
||||
"CraftingBenchCountry": "枫丹",
|
||||
"AdventurersGuildCountry": "璃月",
|
||||
"PartyName": "战斗队",
|
||||
"DailyRewardPartyName": "好感队",
|
||||
"SecretTreasureObjects": ["须臾树脂"],
|
||||
"WeeklyDomainEnabled": True,
|
||||
"DomainName": "旧秘境",
|
||||
"CompletionAction": "关机",
|
||||
},
|
||||
)
|
||||
self._write_json(
|
||||
self.root / "User" / "config.json",
|
||||
{
|
||||
"marker": "preserved",
|
||||
"autoFightConfig": {"strategyName": "策略A"},
|
||||
"autoDomainConfig": {
|
||||
"specifyResinUse": True,
|
||||
"other": 1,
|
||||
},
|
||||
"autoLeyLineOutcropConfig": {
|
||||
"isGoToSynthesizer": True,
|
||||
"team": "战斗队",
|
||||
"friendshipTeam": "",
|
||||
"fightConfig": {"strategyName": "策略A"},
|
||||
},
|
||||
},
|
||||
)
|
||||
strategy = self.root / "User" / "AutoFight" / "策略A.txt"
|
||||
strategy.parent.mkdir(parents=True, exist_ok=True)
|
||||
strategy.write_text("战斗策略", encoding="utf-8")
|
||||
self._write_json(
|
||||
self.root / "User" / "JsScript" / "AutoDomain" / "settings.json",
|
||||
[
|
||||
{
|
||||
"name": "domainName",
|
||||
"type": "select",
|
||||
"options": ["铭记之谷", "仲夏庭园"],
|
||||
}
|
||||
],
|
||||
)
|
||||
self._write_json(
|
||||
self.root / "User" / "ScriptGroup" / "每日委托.json",
|
||||
{"name": "每日委托", "projects": [{"name": "委托", "status": "Enabled"}]},
|
||||
)
|
||||
self._write_json(
|
||||
self.root / "User" / "ScriptGroup" / "切换队伍.json",
|
||||
{
|
||||
"name": "切换队伍",
|
||||
"projects": [
|
||||
{
|
||||
"folderName": "AcceleratedEditionSwitchParty",
|
||||
"status": "Enabled",
|
||||
"jsScriptSettingsObject": {"partyName": "旧队伍", "debug": True},
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
self._write_json(
|
||||
self.root / "User" / "ScriptGroup" / "修改队员.json",
|
||||
{
|
||||
"name": "修改队员",
|
||||
"projects": [
|
||||
{
|
||||
"folderName": "AutoSwitchRoles",
|
||||
"status": "Enabled",
|
||||
"jsScriptSettingsObject": {"position1": ""},
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
options = [
|
||||
"水-单手剑-芙宁娜",
|
||||
"冰-长枪-爱可菲",
|
||||
"草-法器-纳西妲",
|
||||
"雷-长枪-雷电将军",
|
||||
"岩-长枪-钟离",
|
||||
]
|
||||
self._write_json(
|
||||
self.root / "User" / "JsScript" / "AutoSwitchRoles" / "settings.json",
|
||||
[
|
||||
{"name": f"position{index}", "type": "select", "options": ["", *options]}
|
||||
for index in range(1, 5)
|
||||
],
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
self.temp_dir.cleanup()
|
||||
|
||||
@staticmethod
|
||||
def _write_json(path: Path, data):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
|
||||
def _prepare(
|
||||
self,
|
||||
argument: str,
|
||||
*,
|
||||
craft_before: bool = True,
|
||||
commission_use_current_party: bool = False,
|
||||
):
|
||||
return prepare_daily_run(
|
||||
self.root,
|
||||
self.alias_path,
|
||||
argument,
|
||||
template_name="默认配置",
|
||||
managed_name="直播系统自动每日",
|
||||
ley_line_craft_resin_before=craft_before,
|
||||
commission_use_current_party=commission_use_current_party,
|
||||
)
|
||||
|
||||
def test_parse_daily_modes(self):
|
||||
self.assertEqual(parse_daily_request("").mode, DAILY_MODE_NONE)
|
||||
domain = parse_daily_request("秘境 风本")
|
||||
self.assertEqual((domain.mode, domain.domain_name), (DAILY_MODE_DOMAIN, "风本"))
|
||||
ley_line = parse_daily_request("地脉 经验 蒙德")
|
||||
self.assertEqual(
|
||||
(ley_line.mode, ley_line.ley_line_type, ley_line.ley_line_country),
|
||||
(DAILY_MODE_LEY_LINE, "启示之花", "蒙德"),
|
||||
)
|
||||
self.assertEqual(parse_daily_request("委托").mode, DAILY_MODE_COMMISSION)
|
||||
|
||||
def test_parse_rejects_missing_or_unknown_arguments(self):
|
||||
with self.assertRaisesRegex(DailyAutomationError, "需要指定秘境"):
|
||||
parse_daily_request("秘境")
|
||||
with self.assertRaisesRegex(DailyAutomationError, "地脉模式格式"):
|
||||
parse_daily_request("地脉 经验")
|
||||
with self.assertRaisesRegex(DailyAutomationError, "不支持的地脉国家"):
|
||||
parse_daily_request("地脉 摩拉 天空岛")
|
||||
with self.assertRaisesRegex(DailyAutomationError, "仅支持"):
|
||||
parse_daily_request("探索")
|
||||
|
||||
def test_domain_alias_resolves_canonical_and_common_names(self):
|
||||
resolver = DomainAliasResolver(self.alias_path, self.root)
|
||||
self.assertEqual(resolver.resolve("风本"), "铭记之谷")
|
||||
self.assertEqual(resolver.resolve("少女套"), "铭记之谷")
|
||||
self.assertEqual(resolver.resolve("仲夏庭园"), "仲夏庭园")
|
||||
|
||||
def test_domain_alias_collision_is_rejected(self):
|
||||
self._write_json(
|
||||
self.alias_path,
|
||||
{
|
||||
"铭记之谷": ["风本"],
|
||||
"仲夏庭园": ["风 本"],
|
||||
},
|
||||
)
|
||||
with self.assertRaisesRegex(DailyAutomationError, "同时指向"):
|
||||
DomainAliasResolver(self.alias_path, self.root).resolve("风本")
|
||||
|
||||
def test_domain_run_generates_exact_flow_and_corrects_bgi_config(self):
|
||||
prepared = self._prepare("秘境 风本")
|
||||
self.assertEqual(prepared.request.domain_name, "铭记之谷")
|
||||
self.assertEqual(prepared.task_name, "自动每日(秘境:铭记之谷)")
|
||||
updates = {update.path.name: update for update in prepared.updates}
|
||||
corrected = updates["config.json"].data
|
||||
self.assertFalse(corrected["autoDomainConfig"]["specifyResinUse"])
|
||||
self.assertEqual(corrected["autoDomainConfig"]["other"], 1)
|
||||
self.assertEqual(corrected["marker"], "preserved")
|
||||
|
||||
managed = updates["直播系统自动每日.json"].data
|
||||
names = [managed["TaskDefinitions"][task_id] for task_id in managed["TaskOrder"]]
|
||||
self.assertEqual(
|
||||
names,
|
||||
["领取邮件", "合成树脂", "自动秘境", "领取尘歌壶奖励", "领取每日奖励"],
|
||||
)
|
||||
self.assertEqual(
|
||||
managed["TaskOrder"],
|
||||
[
|
||||
"mail-template-id",
|
||||
"craft-template-id",
|
||||
"domain-template-id",
|
||||
"serenitea-template-id",
|
||||
"daily-reward-template-id",
|
||||
],
|
||||
)
|
||||
self.assertFalse(managed["WeeklyDomainEnabled"])
|
||||
self.assertEqual(managed["DomainName"], "铭记之谷")
|
||||
self.assertEqual(managed["CompletionAction"], "无")
|
||||
self.assertEqual(managed["PartyName"], "战斗队")
|
||||
|
||||
def test_no_mode_skips_only_the_other_task(self):
|
||||
prepared = self._prepare("")
|
||||
managed = prepared.updates[-1].data
|
||||
names = [managed["TaskDefinitions"][task_id] for task_id in managed["TaskOrder"]]
|
||||
self.assertEqual(
|
||||
names,
|
||||
["领取邮件", "合成树脂", "领取尘歌壶奖励", "领取每日奖励"],
|
||||
)
|
||||
|
||||
def test_ley_line_run_sets_all_days_and_respects_craft_toggle(self):
|
||||
prepared = self._prepare("地脉 摩拉 枫丹", craft_before=False)
|
||||
updates = {update.path.name: update for update in prepared.updates}
|
||||
corrected = updates["config.json"].data
|
||||
self.assertFalse(corrected["autoLeyLineOutcropConfig"]["isGoToSynthesizer"])
|
||||
managed = updates["直播系统自动每日.json"].data
|
||||
names = [managed["TaskDefinitions"][task_id] for task_id in managed["TaskOrder"]]
|
||||
self.assertEqual(
|
||||
names,
|
||||
["领取邮件", "自动地脉花", "领取尘歌壶奖励", "领取每日奖励"],
|
||||
)
|
||||
self.assertTrue(managed["LeyLineResinExhaustionMode"])
|
||||
self.assertFalse(managed["LeyLineOpenModeCountMin"])
|
||||
for day in ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"):
|
||||
self.assertTrue(managed[f"LeyLineRun{day}"])
|
||||
self.assertEqual(managed[f"LeyLine{day}Type"], "藏金之花")
|
||||
self.assertEqual(managed[f"LeyLine{day}Country"], "枫丹")
|
||||
|
||||
def test_commission_is_added_as_a_configuration_group_task(self):
|
||||
prepared = self._prepare("委托")
|
||||
managed = prepared.updates[-1].data
|
||||
names = [managed["TaskDefinitions"][task_id] for task_id in managed["TaskOrder"]]
|
||||
self.assertEqual(
|
||||
names,
|
||||
["领取邮件", "合成树脂", "每日委托", "领取尘歌壶奖励", "领取每日奖励"],
|
||||
)
|
||||
commission_id = next(
|
||||
task_id
|
||||
for task_id, name in managed["TaskDefinitions"].items()
|
||||
if name == "每日委托"
|
||||
)
|
||||
self.assertNotIn(
|
||||
commission_id,
|
||||
{
|
||||
"mail-template-id",
|
||||
"craft-template-id",
|
||||
"serenitea-template-id",
|
||||
"daily-reward-template-id",
|
||||
},
|
||||
)
|
||||
def test_commission_requires_nonempty_group(self):
|
||||
(self.root / "User" / "ScriptGroup" / "每日委托.json").unlink()
|
||||
with self.assertRaisesRegex(DailyAutomationError, "每日委托配置组"):
|
||||
self._prepare("委托")
|
||||
|
||||
def test_auto_commission_nova_requires_complete_first_run_config(self):
|
||||
self._write_json(
|
||||
self.root / "User" / "ScriptGroup" / "每日委托.json",
|
||||
{
|
||||
"name": "每日委托",
|
||||
"projects": [
|
||||
{
|
||||
"folderName": "AutoCommissionNova",
|
||||
"status": "Enabled",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
with self.assertRaisesRegex(DailyAutomationError, "缺少 Data/user-config.json"):
|
||||
self._prepare("委托")
|
||||
|
||||
user_config_path = (
|
||||
self.root
|
||||
/ "User"
|
||||
/ "JsScript"
|
||||
/ "AutoCommissionNova"
|
||||
/ "Data"
|
||||
/ "user-config.json"
|
||||
)
|
||||
self._write_json(
|
||||
user_config_path,
|
||||
{
|
||||
"party": {
|
||||
"global": {
|
||||
"battleTeamName": "战斗队",
|
||||
"elementTeamName": "",
|
||||
"battleStrategy": "策略A",
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
with self.assertRaisesRegex(DailyAutomationError, "元素采集队伍"):
|
||||
self._prepare("委托")
|
||||
|
||||
self._write_json(
|
||||
user_config_path,
|
||||
{
|
||||
"party": {
|
||||
"global": {
|
||||
"battleTeamName": "战斗队",
|
||||
"elementTeamName": "采集队",
|
||||
"battleStrategy": "策略A",
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertEqual(self._prepare("委托").request.mode, DAILY_MODE_COMMISSION)
|
||||
|
||||
def test_auto_commission_nova_can_inject_current_party_for_battle_and_collection(self):
|
||||
self._write_json(
|
||||
self.root / "User" / "ScriptGroup" / "每日委托.json",
|
||||
{
|
||||
"name": "每日委托",
|
||||
"projects": [
|
||||
{
|
||||
"folderName": "AutoCommissionNova",
|
||||
"status": "Enabled",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
user_config_path = (
|
||||
self.root
|
||||
/ "User"
|
||||
/ "JsScript"
|
||||
/ "AutoCommissionNova"
|
||||
/ "Data"
|
||||
/ "user-config.json"
|
||||
)
|
||||
self._write_json(
|
||||
user_config_path,
|
||||
{
|
||||
"marker": "preserved",
|
||||
"party": {
|
||||
"global": {
|
||||
"battleTeamName": "",
|
||||
"elementTeamName": "",
|
||||
"battleStrategy": "策略A",
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
prepared = self._prepare("委托", commission_use_current_party=True)
|
||||
self.assertTrue(prepared.requires_current_party)
|
||||
|
||||
update = prepare_commission_current_party_update(self.root, "当前队伍")
|
||||
self.assertEqual(
|
||||
update.data["party"]["global"]["battleTeamName"],
|
||||
"当前队伍",
|
||||
)
|
||||
self.assertEqual(
|
||||
update.data["party"]["global"]["elementTeamName"],
|
||||
"当前队伍",
|
||||
)
|
||||
self.assertEqual(update.data["marker"], "preserved")
|
||||
|
||||
def test_switch_party_updates_only_target_setting(self):
|
||||
update = prepare_switch_party_update(self.root, "深渊队")
|
||||
project = update.data["projects"][0]
|
||||
self.assertEqual(project["jsScriptSettingsObject"]["partyName"], "深渊队")
|
||||
self.assertTrue(project["jsScriptSettingsObject"]["debug"])
|
||||
|
||||
def test_edit_party_accepts_separators_and_contiguous_names(self):
|
||||
separated, display = resolve_party_members(
|
||||
self.root,
|
||||
"芙宁娜 爱可菲 纳西妲 雷电将军",
|
||||
)
|
||||
self.assertEqual(display, ["芙宁娜", "爱可菲", "纳西妲", "雷电将军"])
|
||||
contiguous, contiguous_display = resolve_party_members(
|
||||
self.root,
|
||||
"芙宁娜爱可菲纳西妲雷电将军",
|
||||
)
|
||||
self.assertEqual(contiguous, separated)
|
||||
self.assertEqual(contiguous_display, display)
|
||||
|
||||
update, names = prepare_edit_party_update(
|
||||
self.root,
|
||||
"芙宁娜、爱可菲、纳西妲、雷电将军",
|
||||
)
|
||||
settings = update.data["projects"][0]["jsScriptSettingsObject"]
|
||||
self.assertEqual(names, ("芙宁娜", "爱可菲", "纳西妲", "雷电将军"))
|
||||
self.assertEqual(settings["position4"], "雷-长枪-雷电将军")
|
||||
|
||||
def test_edit_party_supports_auto_switch_roles_67_character_data(self):
|
||||
self._write_json(
|
||||
self.root / "User" / "JsScript" / "AutoSwitchRoles" / "settings.json",
|
||||
[
|
||||
{"name": f"position{index}", "type": "input-text", "default": ""}
|
||||
for index in range(1, 5)
|
||||
],
|
||||
)
|
||||
self._write_json(
|
||||
self.root / "User" / "JsScript" / "AutoSwitchRoles" / "combat_avatar.json",
|
||||
[
|
||||
{"name": "神里绫华", "alias": ["绫华"]},
|
||||
{"name": "申鹤", "alias": []},
|
||||
{"name": "枫原万叶", "alias": ["万叶"]},
|
||||
{"name": "珊瑚宫心海", "alias": ["心海"]},
|
||||
],
|
||||
)
|
||||
|
||||
update, names = prepare_edit_party_update(
|
||||
self.root,
|
||||
"绫华 申鹤 万叶 心海",
|
||||
)
|
||||
|
||||
settings = update.data["projects"][0]["jsScriptSettingsObject"]
|
||||
self.assertEqual(names, ("神里绫华", "申鹤", "枫原万叶", "珊瑚宫心海"))
|
||||
self.assertEqual(
|
||||
[settings[f"position{index}"] for index in range(1, 5)],
|
||||
["神里绫华", "申鹤", "枫原万叶", "珊瑚宫心海"],
|
||||
)
|
||||
|
||||
resolved, display = resolve_party_members(
|
||||
self.root,
|
||||
"神里绫华申鹤枫原万叶珊瑚宫心海",
|
||||
)
|
||||
self.assertEqual(resolved, list(display))
|
||||
|
||||
def test_edit_party_rejects_ambiguous_combat_avatar_alias(self):
|
||||
self._write_json(
|
||||
self.root / "User" / "JsScript" / "AutoSwitchRoles" / "settings.json",
|
||||
[
|
||||
{"name": f"position{index}", "type": "input-text", "default": ""}
|
||||
for index in range(1, 5)
|
||||
],
|
||||
)
|
||||
self._write_json(
|
||||
self.root / "User" / "JsScript" / "AutoSwitchRoles" / "combat_avatar.json",
|
||||
[
|
||||
{"name": "角色甲", "alias": ["同名"]},
|
||||
{"name": "角色乙", "alias": ["同名"]},
|
||||
{"name": "角色丙", "alias": []},
|
||||
{"name": "角色丁", "alias": []},
|
||||
{"name": "角色戊", "alias": []},
|
||||
],
|
||||
)
|
||||
|
||||
with self.assertRaisesRegex(DailyAutomationError, "未知或有歧义"):
|
||||
resolve_party_members(self.root, "同名 角色丙 角色丁 角色戊")
|
||||
|
||||
def test_edit_party_requires_four_distinct_known_members(self):
|
||||
with self.assertRaisesRegex(DailyAutomationError, "必须是4人"):
|
||||
resolve_party_members(self.root, "芙宁娜 爱可菲 纳西妲")
|
||||
with self.assertRaisesRegex(DailyAutomationError, "不能重复"):
|
||||
resolve_party_members(self.root, "芙宁娜 芙宁娜 纳西妲 雷电将军")
|
||||
with self.assertRaisesRegex(DailyAutomationError, "未知"):
|
||||
resolve_party_members(self.root, "芙宁娜 爱可菲 纳西妲 不存在")
|
||||
|
||||
def test_apply_json_updates_writes_managed_files(self):
|
||||
prepared = self._prepare("秘境 风本")
|
||||
apply_json_updates(prepared.updates)
|
||||
bgi_config = json.loads((self.root / "User" / "config.json").read_text(encoding="utf-8"))
|
||||
managed = json.loads(
|
||||
(self.root / "User" / "OneDragon" / "直播系统自动每日.json").read_text(encoding="utf-8")
|
||||
)
|
||||
self.assertFalse(bgi_config["autoDomainConfig"]["specifyResinUse"])
|
||||
self.assertEqual(managed["DomainName"], "铭记之谷")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user