""" 测试所有验证码生成器。 每种生成器 generate() 1 张 → 验证返回类型、图片尺寸、标签格式。 """ import re import pytest from PIL import Image from config import GENERATE_CONFIG, NORMAL_CHARS, MATH_CHARS, THREED_CHARS, SOLVER_CONFIG from generators import ( NormalCaptchaGenerator, MathCaptchaGenerator, ThreeDCaptchaGenerator, ThreeDRotateGenerator, ThreeDSliderGenerator, SlideDataGenerator, RotateSolverDataGenerator, ) class TestNormalCaptchaGenerator: def setup_method(self): self.gen = NormalCaptchaGenerator(seed=0) self.cfg = GENERATE_CONFIG["normal"] def test_generate_returns_image_and_label(self): img, label = self.gen.generate() assert isinstance(img, Image.Image) assert isinstance(label, str) def test_image_size(self): img, _ = self.gen.generate() w, h = self.cfg["image_size"] assert img.size == (w, h) def test_label_chars_in_charset(self): img, label = self.gen.generate() assert len(label) >= 4 for ch in label: assert ch in NORMAL_CHARS, f"char {ch!r} not in NORMAL_CHARS" def test_generate_with_text(self): img, label = self.gen.generate(text="AB12") assert label == "AB12" class TestMathCaptchaGenerator: def setup_method(self): self.gen = MathCaptchaGenerator(seed=0) self.cfg = GENERATE_CONFIG["math"] def test_generate_returns_image_and_label(self): img, label = self.gen.generate() assert isinstance(img, Image.Image) assert isinstance(label, str) def test_image_size(self): img, _ = self.gen.generate() w, h = self.cfg["image_size"] assert img.size == (w, h) def test_label_is_expression(self): """Label should be like '3+8' (expression without =? and without result).""" img, label = self.gen.generate() assert re.match(r"^\d+[+\-×÷]\d+$", label), f"unexpected label format: {label!r}" class TestThreeDCaptchaGenerator: def setup_method(self): self.gen = ThreeDCaptchaGenerator(seed=0) self.cfg = GENERATE_CONFIG["3d_text"] def test_generate_returns_image_and_label(self): img, label = self.gen.generate() assert isinstance(img, Image.Image) assert isinstance(label, str) def test_image_size(self): img, _ = self.gen.generate() w, h = self.cfg["image_size"] assert img.size == (w, h) def test_label_chars_in_charset(self): img, label = self.gen.generate() assert len(label) >= 4 for ch in label: assert ch in THREED_CHARS, f"char {ch!r} not in THREED_CHARS" class TestThreeDRotateGenerator: def setup_method(self): self.gen = ThreeDRotateGenerator(seed=0) self.cfg = GENERATE_CONFIG["3d_rotate"] def test_generate_returns_image_and_label(self): img, label = self.gen.generate() assert isinstance(img, Image.Image) assert isinstance(label, str) def test_image_size(self): img, _ = self.gen.generate() w, h = self.cfg["image_size"] assert img.size == (w, h) def test_label_is_angle(self): img, label = self.gen.generate() angle = int(label) assert 0 <= angle <= 359 class TestThreeDSliderGenerator: def setup_method(self): self.gen = ThreeDSliderGenerator(seed=0) self.cfg = GENERATE_CONFIG["3d_slider"] def test_generate_returns_image_and_label(self): img, label = self.gen.generate() assert isinstance(img, Image.Image) assert isinstance(label, str) def test_image_size(self): img, _ = self.gen.generate() w, h = self.cfg["image_size"] assert img.size == (w, h) def test_label_is_offset(self): img, label = self.gen.generate() offset = int(label) lo, hi = self.cfg["gap_x_range"] assert lo <= offset <= hi class TestSlideDataGenerator: def setup_method(self): self.gen = SlideDataGenerator(seed=0) def test_generate_returns_image_and_label(self): img, label = self.gen.generate() assert isinstance(img, Image.Image) assert isinstance(label, str) def test_image_size(self): img, _ = self.gen.generate() h, w = SOLVER_CONFIG["slide"]["cnn_input_size"] assert img.size == (w, h) def test_label_is_numeric(self): img, label = self.gen.generate() val = int(label) assert val >= 0 class TestRotateSolverDataGenerator: def setup_method(self): self.gen = RotateSolverDataGenerator(seed=0) def test_generate_returns_image_and_label(self): img, label = self.gen.generate() assert isinstance(img, Image.Image) assert isinstance(label, str) def test_image_size(self): img, _ = self.gen.generate() h, w = SOLVER_CONFIG["rotate"]["input_size"] assert img.size == (w, h) def test_label_is_angle(self): img, label = self.gen.generate() angle = int(label) assert 0 <= angle <= 359