"""Behavioral coverage for beta 1.0.5 primogem economy.""" from __future__ import annotations import json import tempfile import unittest from datetime import datetime from pathlib import Path from unittest import mock from test_jwebot_edge import MODULE, config class Release105PrimogemTests(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() self.engine = MODULE.EdgeApplication(config(Path(self.temp.name))) self.counter = 0 def tearDown(self): self.engine.close() self.temp.cleanup() def command(self, question, *, sender="Alice", event_id=None): self.counter += 1 row = { "question": question, "sender": sender, "group_fingerprint": "group-a", "event_id": event_id or f"primogem-{self.counter}", } return self.engine.local.handle(row, {}) def state(self, sender="Alice"): key = self.engine.ledger.resolve_person("group-a", sender)["person_key"] row = self.engine.ledger.connection.execute( """ SELECT state_json FROM player_accounts WHERE group_fingerprint = ? AND person_key = ? """, ("group-a", key), ).fetchone() self.assertIsNotNone(row) return json.loads(row[0]) @staticmethod def blackjack_deck(*prefix): used = set(prefix) return list(prefix) + [card for card in range(52) if card not in used] def test_natural_blackjack_grants_primogem_and_wish_can_award_scan_ticket(self): deck = self.blackjack_deck(0, 12, 1, 2) def shuffle(cards): cards[:] = deck with mock.patch.object(self.engine.local.players.rng, "shuffle", shuffle): result = self.command("/21点 开始 10") self.assertIn("+1 原石", result) self.assertEqual(self.state()["primogems"], 1) with mock.patch.object( self.engine.local.players.rng, "randrange", side_effect=[0, 0], ): wish = self.command("/原石祈愿") self.assertIn("抽到 20 摩拉", wish) self.assertIn("扫码概率券 1 张", wish) state = self.state() self.assertEqual(state["primogems"], 0) self.assertEqual(state["scan_boost_tickets"], 1) def test_extreme_blackjack_hit_from_20_to_21_grants_two_primogems(self): prefix = [9, 12, 1, 2] deck = self.blackjack_deck(*prefix, 0) deck = deck[:4] + [card for card in deck[4:] if card != 0] + [0] def shuffle(cards): cards[:] = deck with mock.patch.object(self.engine.local.players.rng, "shuffle", shuffle): self.command("/21点 开始 10") self.command("/21点 要牌") result = self.command("/21点 停牌") self.assertIn("21点极限挑战", result) self.assertIn("+2 原石", result) self.assertEqual(self.state()["primogems"], 2) def test_lottery_two_consecutive_personal_draws_with_five_total_hits(self): self.command("/彩票开始") self.command("/彩票34710") with mock.patch.object( self.engine.local.players.rng, "sample", return_value=[3, 7, 9], ): self.command("/彩票开奖") self.command("/彩票开始", event_id="lottery-start-two") self.command("/彩票34710", event_id="lottery-entry-two") with mock.patch.object( self.engine.local.players.rng, "sample", return_value=[3, 4, 7], ): result = self.command("/彩票开奖", event_id="lottery-draw-two") self.assertIn("彩票三中挑战", result) self.assertEqual(self.state()["primogems"], 2) def test_scan_boost_and_taffy_say_spend_primogem_resources(self): self.command("/原石") account = self.state() account["primogems"] = 3 self.engine.ledger._save_player_account( "group-a", self.engine.ledger.resolve_person("group-a", "Alice")["person_key"], account, MODULE.utc_now(), ) self.engine.ledger.connection.commit() boost = self.command("/扫码加权 Bob") self.assertIn("已给 bob 增加整点扫码权重", boost) boost_targets = self.engine.ledger.active_scan_boost_targets("group-a") bob_key = self.engine.ledger.resolve_person("group-a", "Bob")["person_key"] self.assertIn(bob_key, boost_targets) ranking = self.command("/扫码榜", event_id="scan-ranking-after-boost") self.assertIn("下一小时扫码权重:", ranking) self.assertIn("bob 6", ranking) second_boost = self.command("/扫码加权 Bob", event_id="scan-boost-second") self.assertIn("已给 bob 增加整点扫码权重", second_boost) stacked = self.command("/扫码榜", event_id="scan-ranking-stacked") self.assertIn("bob 11", stacked) speech = self.command("/Taffy发话 今天也要加班吗") self.assertEqual(speech, "Taffy:今天也要加班吗喵") state = self.state() self.assertEqual(state["primogems"], 0) self.assertEqual(state["taffy_say_credits"], 1) def test_scheduled_taffy_speech_uses_clock_delivery_queue(self): self.command("/原石") account = self.state() account["primogems"] = 1 person_key = self.engine.ledger.resolve_person("group-a", "Alice")["person_key"] self.engine.ledger._save_player_account( "group-a", person_key, account, MODULE.utc_now(), ) self.engine.ledger.connection.commit() scheduled_at = datetime( 2026, 10, 16, 8, 0, tzinfo=MODULE.BEIJING_TIMEZONE, ) response = self.engine.ledger.player_taffy_say( "group-a", "Alice", "scheduled-taffy", "taffy_say:test", "准点提醒", scheduled_at.timestamp(), lambda data: self.engine.local.players.render_taffy_say(data, "alice"), ) self.assertIn("已安排Taffy", response) delivered = [] self.engine.deliver = lambda row: delivered.append(row["result_text"]) self.assertTrue( self.engine.process_clock_once( now=scheduled_at, group_fingerprint="group-a", ) ) self.assertEqual(delivered, ["Taffy:准点提醒"]) if __name__ == "__main__": unittest.main()