diff --git a/tests/test_automate.py b/tests/test_automate.py new file mode 100644 index 0000000..9e167e8 --- /dev/null +++ b/tests/test_automate.py @@ -0,0 +1,153 @@ +"""automate.py 的 Pillow 图像分析函数回归测试。 + +覆盖:detect_card_rows 行检测、count_blue_pixels 蓝勾检测、 +sample_rgb_from_file 像素采样、std_profile 标准差剖面、 +date_label_hash / screenshot_hash 哈希稳定性。 + +这些测试用合成图片验证逻辑,不需要启动模拟器。 +""" +import os +import random +import tempfile +import unittest + +from PIL import Image, ImageDraw + +# 把项目根目录加入 path +import sys +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import automate + + +class TestDetectCardRows(unittest.TestCase): + def test_detects_three_rows(self): + img = Image.new("RGB", (1080, 2400), (240, 240, 240)) + random.seed(42) + for row_top in [1060, 1280, 1500]: + for y in range(row_top, row_top + 180): + for x in range(100, 980): + img.putpixel((x, y), ( + random.randint(50, 200), + random.randint(50, 200), + random.randint(50, 200), + )) + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: + path = f.name + try: + img.save(path) + rows = automate.detect_card_rows(path) + self.assertEqual(len(rows), 3) + for expected, actual in zip([1150, 1370, 1590], rows): + self.assertLess(abs(expected - actual), 20) + finally: + os.unlink(path) + + def test_empty_image_returns_no_rows(self): + img = Image.new("RGB", (1080, 2400), (200, 200, 200)) + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: + path = f.name + try: + img.save(path) + rows = automate.detect_card_rows(path) + self.assertEqual(rows, []) + finally: + os.unlink(path) + + +class TestCountBluePixels(unittest.TestCase): + def test_blue_badge_detected(self): + img = Image.new("RGB", (1080, 2400), (200, 200, 200)) + draw = ImageDraw.Draw(img) + draw.rectangle([500, 1160, 580, 1240], fill=(100, 143, 252)) + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: + path = f.name + try: + img.save(path) + cnt = automate.count_blue_pixels(path, 540, 1200) + self.assertGreaterEqual(cnt, 500) + finally: + os.unlink(path) + + def test_gray_area_not_detected(self): + img = Image.new("RGB", (1080, 2400), (200, 200, 200)) + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: + path = f.name + try: + img.save(path) + cnt = automate.count_blue_pixels(path, 200, 1200) + self.assertLess(cnt, 500) + finally: + os.unlink(path) + + +class TestSampleRgb(unittest.TestCase): + def test_sample_pixel(self): + img = Image.new("RGB", (100, 100), (0, 0, 0)) + img.putpixel((50, 50), (255, 128, 64)) + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: + path = f.name + try: + img.save(path) + rgb = automate.sample_rgb_from_file(path, 50, 50) + self.assertEqual(rgb, (255, 128, 64)) + finally: + os.unlink(path) + + def test_out_of_bounds_returns_zero(self): + img = Image.new("RGB", (10, 10), (10, 20, 30)) + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: + path = f.name + try: + img.save(path) + rgb = automate.sample_rgb_from_file(path, 999, 999) + self.assertEqual(rgb, (0, 0, 0)) + finally: + os.unlink(path) + + +class TestStdProfile(unittest.TestCase): + def test_textured_rows_have_high_std(self): + img = Image.new("RGB", (1080, 2400), (240, 240, 240)) + random.seed(123) + for y in range(1100, 1300): + for x in range(350, 1050): + img.putpixel((x, y), (random.randint(0, 255),) * 3) + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: + path = f.name + try: + img.save(path) + prof = automate.std_profile(path) + textured = sum(1 for _, s in prof if s >= 28) + self.assertGreater(textured, 100) + finally: + os.unlink(path) + + +class TestHashStability(unittest.TestCase): + def test_date_label_hash_stable(self): + img = Image.new("RGB", (1080, 2400), (100, 150, 200)) + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: + path = f.name + try: + img.save(path) + h1 = automate.date_label_hash(path) + h2 = automate.date_label_hash(path) + self.assertEqual(h1, h2) + finally: + os.unlink(path) + + def test_screenshot_hash_stable(self): + img = Image.new("RGB", (1080, 2400), (100, 150, 200)) + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: + path = f.name + try: + img.save(path) + h1 = automate.screenshot_hash(path) + h2 = automate.screenshot_hash(path) + self.assertEqual(h1, h2) + finally: + os.unlink(path) + + +if __name__ == "__main__": + unittest.main()