import unittest from pathlib import Path from PIL import Image from automation.engine import Matcher, Region, WorkflowError, load_flow from automation.offers import OfferRunner ROOT = Path(__file__).resolve().parent.parent class OfferDesktop: def __init__(self, images): self.images = images self.index = 0 self.clicks = [] def screenshot(self): return self.images[min(self.index, len(self.images) - 1)] def click(self, point, region, size): self.clicks.append(point) self.index += 1 class OfferTests(unittest.TestCase): def setUp(self): self.flow = load_flow(ROOT / 'workflows/offer_claim.json') self.matcher = Matcher(ROOT / 'assets') self.region = Region(0, 0, 562, 1002) def image(self, name): image = Image.new('RGB', (562, 1002), (45, 62, 78)) for spec in self.flow['states'][name]: template = Image.open(ROOT / 'assets' / spec['template']).convert('RGB') x, y, _, _ = spec['search'] image.paste(template, (x + 5, y + 5)) return image def runner(self, names): desktop = OfferDesktop([self.image(n) for n in names]) runner = OfferRunner(desktop, self.matcher, self.flow, lambda _: self.region, log=lambda _: None, timeout=0.8) return desktop, runner def test_full_claim_and_return(self): desktop, runner = self.runner(['home', 'available', 'reward', 'claimed', 'home']) self.assertEqual(runner.run(), 'claimed') self.assertEqual(desktop.clicks, [self.flow['clicks'][n] for n in ('open', 'claim', 'dismiss', 'back')]) def test_already_claimed_does_not_claim_again(self): desktop, runner = self.runner(['home', 'claimed', 'home']) self.assertEqual(runner.run(), 'already_claimed') self.assertEqual(desktop.clicks, [self.flow['clicks'][n] for n in ('open', 'back')]) def test_monthcard_entry_selects_battlepass(self): desktop, runner = self.runner(['home', 'menu', 'claimed', 'home']) self.assertEqual(runner.run(), 'already_claimed') self.assertEqual(desktop.clicks, [self.flow['clicks'][n] for n in ('open', 'battlepass', 'back')]) def test_missing_reward_stops_without_retry(self): desktop, runner = self.runner(['home', 'available', 'available']) with self.assertRaises(WorkflowError): runner.run() self.assertEqual(desktop.clicks, [self.flow['clicks'][n] for n in ('open', 'claim')]) def test_preview_never_clicks(self): desktop, runner = self.runner(['home']) self.assertEqual(runner.run(True), 'preview') self.assertEqual(desktop.clicks, []) def test_window_movement_blocks_stale_click(self): desktop, runner = self.runner(['home']) observation = ('home', desktop.screenshot(), self.region) runner.region_provider = lambda _: Region(2, 0, 562, 1002) with self.assertRaises(WorkflowError): runner.click('open', observation) self.assertEqual(desktop.clicks, []) if __name__ == '__main__': unittest.main()