test: 新增automate.py Pillow图像函数回归测试(9个用例)
覆盖 detect_card_rows 行检测、count_blue_pixels 蓝勾检测、 sample_rgb_from_file 像素采样、std_profile 标准差剖面、 date_label_hash/screenshot_hash 哈希稳定性。全部通过。
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user