Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f8de295b6d |
Executable
+675
@@ -0,0 +1,675 @@
|
||||
"""sticker_config 单元测试 - wave167
|
||||
|
||||
覆盖:
|
||||
- ImageStickerConfig 数据类 / from_dict / has_time_range / end_time
|
||||
- TextStickerConfig 数据类 / from_dict / has_background / has_time_range
|
||||
- StickerOverlayResult 数据类
|
||||
- resolve_sticker_position 位置解析(9宫格/自定义坐标/单位转换/钳制)
|
||||
- parse_stickers_from_config 贴纸列表解析
|
||||
- get_sticker_categories 分类列表
|
||||
- 常量验证(POSITION_PRESETS / STICKER_CATEGORIES)
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from packages.domain.sticker_config import (
|
||||
POSITION_PRESETS,
|
||||
STICKER_CATEGORIES,
|
||||
ImageStickerConfig,
|
||||
StickerOverlayResult,
|
||||
TextStickerConfig,
|
||||
get_sticker_categories,
|
||||
parse_stickers_from_config,
|
||||
resolve_sticker_position,
|
||||
)
|
||||
|
||||
# ============================================================
|
||||
# 常量验证
|
||||
# ============================================================
|
||||
|
||||
|
||||
class TestConstants:
|
||||
def test_nine_position_presets(self):
|
||||
assert len(POSITION_PRESETS) == 9
|
||||
|
||||
def test_positions_in_normalized_range(self):
|
||||
for name, (x, y) in POSITION_PRESETS.items():
|
||||
assert 0.0 <= x <= 1.0, f"{name} x out of range: {x}"
|
||||
assert 0.0 <= y <= 1.0, f"{name} y out of range: {y}"
|
||||
|
||||
def test_top_left_is_near_zero(self):
|
||||
x, y = POSITION_PRESETS["top_left"]
|
||||
assert x < 0.1
|
||||
assert y < 0.1
|
||||
|
||||
def test_bottom_right_is_near_one(self):
|
||||
x, y = POSITION_PRESETS["bottom_right"]
|
||||
assert x > 0.9
|
||||
assert y > 0.9
|
||||
|
||||
def test_center_is_middle(self):
|
||||
x, y = POSITION_PRESETS["center"]
|
||||
assert x == 0.5
|
||||
assert y == 0.5
|
||||
|
||||
def test_sticker_categories_not_empty(self):
|
||||
assert len(STICKER_CATEGORIES) >= 3
|
||||
|
||||
def test_sticker_categories_format(self):
|
||||
for cat in STICKER_CATEGORIES:
|
||||
assert len(cat) == 2
|
||||
assert isinstance(cat[0], str)
|
||||
assert isinstance(cat[1], str)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ImageStickerConfig
|
||||
# ============================================================
|
||||
|
||||
|
||||
class TestImageStickerConfigDefaults:
|
||||
def test_default_values(self):
|
||||
cfg = ImageStickerConfig()
|
||||
assert cfg.enabled is False
|
||||
assert cfg.type == "image"
|
||||
assert cfg.position == "top_right"
|
||||
assert cfg.x is None
|
||||
assert cfg.y is None
|
||||
assert cfg.x_unit == "percent"
|
||||
assert cfg.y_unit == "percent"
|
||||
assert cfg.scale == 1.0
|
||||
assert cfg.width is None
|
||||
assert cfg.height is None
|
||||
assert cfg.opacity == 1.0
|
||||
assert cfg.start_time == 0.0
|
||||
assert cfg.duration == 0.0
|
||||
assert cfg.fade_in == 0.0
|
||||
assert cfg.fade_out == 0.0
|
||||
assert cfg.z_index == 10
|
||||
assert cfg.image_url == ""
|
||||
assert cfg.preset_id == ""
|
||||
|
||||
def test_has_time_range_false_when_zero(self):
|
||||
cfg = ImageStickerConfig()
|
||||
assert cfg.has_time_range is False
|
||||
|
||||
def test_has_time_range_true_when_set(self):
|
||||
cfg = ImageStickerConfig(duration=5.0)
|
||||
assert cfg.has_time_range is True
|
||||
|
||||
def test_end_time_calculation(self):
|
||||
cfg = ImageStickerConfig(start_time=2.0, duration=3.0)
|
||||
assert cfg.end_time == pytest.approx(5.0)
|
||||
|
||||
def test_end_time_zero_duration(self):
|
||||
cfg = ImageStickerConfig(start_time=5.0, duration=0.0)
|
||||
assert cfg.end_time == pytest.approx(5.0)
|
||||
|
||||
|
||||
class TestImageStickerFromDict:
|
||||
def test_none_returns_default(self):
|
||||
cfg = ImageStickerConfig.from_dict(None)
|
||||
assert cfg.enabled is False
|
||||
assert cfg.position == "top_right"
|
||||
|
||||
def test_empty_dict_returns_default(self):
|
||||
cfg = ImageStickerConfig.from_dict({})
|
||||
assert cfg.enabled is False
|
||||
|
||||
def test_not_dict_returns_default(self):
|
||||
cfg = ImageStickerConfig.from_dict("not_a_dict")
|
||||
assert cfg.enabled is False
|
||||
|
||||
def test_enabled_true(self):
|
||||
cfg = ImageStickerConfig.from_dict({"enabled": True})
|
||||
assert cfg.enabled is True
|
||||
|
||||
def test_position_custom(self):
|
||||
cfg = ImageStickerConfig.from_dict({"position": "bottom_left"})
|
||||
assert cfg.position == "bottom_left"
|
||||
|
||||
def test_custom_coordinates(self):
|
||||
cfg = ImageStickerConfig.from_dict({"x": 30.0, "y": 50.0})
|
||||
assert cfg.x == 30.0
|
||||
assert cfg.y == 50.0
|
||||
|
||||
def test_string_coordinates_converted(self):
|
||||
cfg = ImageStickerConfig.from_dict({"x": "25.5", "y": "75.0"})
|
||||
assert cfg.x == 25.5
|
||||
assert cfg.y == 75.0
|
||||
|
||||
def test_invalid_coordinates_become_none(self):
|
||||
cfg = ImageStickerConfig.from_dict({"x": "invalid", "y": "abc"})
|
||||
assert cfg.x is None
|
||||
assert cfg.y is None
|
||||
|
||||
def test_scale_clamped_min(self):
|
||||
cfg = ImageStickerConfig.from_dict({"scale": 0.001})
|
||||
assert cfg.scale == 0.01
|
||||
|
||||
def test_scale_normal(self):
|
||||
cfg = ImageStickerConfig.from_dict({"scale": 1.5})
|
||||
assert cfg.scale == 1.5
|
||||
|
||||
def test_opacity_clamped_high(self):
|
||||
cfg = ImageStickerConfig.from_dict({"opacity": 1.5})
|
||||
assert cfg.opacity == 1.0
|
||||
|
||||
def test_opacity_clamped_low(self):
|
||||
cfg = ImageStickerConfig.from_dict({"opacity": -0.5})
|
||||
assert cfg.opacity == 0.0
|
||||
|
||||
def test_opacity_normal(self):
|
||||
cfg = ImageStickerConfig.from_dict({"opacity": 0.5})
|
||||
assert cfg.opacity == 0.5
|
||||
|
||||
def test_start_time_clamped_non_negative(self):
|
||||
cfg = ImageStickerConfig.from_dict({"start_time": -5.0})
|
||||
assert cfg.start_time == 0.0
|
||||
|
||||
def test_duration_clamped_non_negative(self):
|
||||
cfg = ImageStickerConfig.from_dict({"duration": -3.0})
|
||||
assert cfg.duration == 0.0
|
||||
|
||||
def test_fade_in_non_negative(self):
|
||||
cfg = ImageStickerConfig.from_dict({"fade_in": -1.0})
|
||||
assert cfg.fade_in == 0.0
|
||||
|
||||
def test_fade_out_non_negative(self):
|
||||
cfg = ImageStickerConfig.from_dict({"fade_out": -1.0})
|
||||
assert cfg.fade_out == 0.0
|
||||
|
||||
def test_z_index_default_when_zero(self):
|
||||
cfg = ImageStickerConfig.from_dict({"z_index": 0})
|
||||
# 0 or None → 10
|
||||
assert cfg.z_index == 10
|
||||
|
||||
def test_z_index_custom(self):
|
||||
cfg = ImageStickerConfig.from_dict({"z_index": 5})
|
||||
assert cfg.z_index == 5
|
||||
|
||||
def test_width_height(self):
|
||||
cfg = ImageStickerConfig.from_dict({"width": 200, "height": 100})
|
||||
assert cfg.width == 200
|
||||
assert cfg.height == 100
|
||||
|
||||
def test_width_height_none(self):
|
||||
cfg = ImageStickerConfig.from_dict({})
|
||||
assert cfg.width is None
|
||||
assert cfg.height is None
|
||||
|
||||
def test_image_url_and_preset_id(self):
|
||||
cfg = ImageStickerConfig.from_dict({"image_url": "http://img.png", "preset_id": "sticker_001"})
|
||||
assert cfg.image_url == "http://img.png"
|
||||
assert cfg.preset_id == "sticker_001"
|
||||
|
||||
def test_units_custom(self):
|
||||
cfg = ImageStickerConfig.from_dict({"x_unit": "pixel", "y_unit": "pixel"})
|
||||
assert cfg.x_unit == "pixel"
|
||||
assert cfg.y_unit == "pixel"
|
||||
|
||||
def test_invalid_numeric_values_use_default(self):
|
||||
cfg = ImageStickerConfig.from_dict({"scale": "not_a_number"})
|
||||
assert cfg.scale == 1.0 # 回退到默认值
|
||||
|
||||
def test_invalid_int_values_use_default(self):
|
||||
cfg = ImageStickerConfig.from_dict({"z_index": "invalid"})
|
||||
assert cfg.z_index == 10
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TextStickerConfig
|
||||
# ============================================================
|
||||
|
||||
|
||||
class TestTextStickerConfigDefaults:
|
||||
def test_default_values(self):
|
||||
cfg = TextStickerConfig()
|
||||
assert cfg.enabled is False
|
||||
assert cfg.type == "text"
|
||||
assert cfg.text == ""
|
||||
assert cfg.font_size == 36
|
||||
assert cfg.font_color == "#FFFFFF"
|
||||
assert cfg.font_family == "sans"
|
||||
assert cfg.stroke_color == "#000000"
|
||||
assert cfg.stroke_width == 2
|
||||
assert cfg.shadow_color == "#000000"
|
||||
assert cfg.shadow_x == 2
|
||||
assert cfg.shadow_y == 2
|
||||
assert cfg.shadow_alpha == 0.5
|
||||
assert cfg.position == "center"
|
||||
assert cfg.start_time == 0.0
|
||||
assert cfg.duration == 0.0
|
||||
assert cfg.z_index == 10
|
||||
assert cfg.bg_color == ""
|
||||
assert cfg.bg_padding == 8
|
||||
assert cfg.bg_alpha == 0.8
|
||||
assert cfg.bg_corner_radius == 8
|
||||
|
||||
def test_has_background_false_when_empty(self):
|
||||
cfg = TextStickerConfig()
|
||||
assert cfg.has_background is False
|
||||
|
||||
def test_has_background_true_when_set(self):
|
||||
cfg = TextStickerConfig(bg_color="#FF0000")
|
||||
assert cfg.has_background is True
|
||||
|
||||
def test_has_time_range_false(self):
|
||||
cfg = TextStickerConfig()
|
||||
assert cfg.has_time_range is False
|
||||
|
||||
def test_has_time_range_true(self):
|
||||
cfg = TextStickerConfig(duration=10.0)
|
||||
assert cfg.has_time_range is True
|
||||
|
||||
|
||||
class TestTextStickerFromDict:
|
||||
def test_none_returns_default(self):
|
||||
cfg = TextStickerConfig.from_dict(None)
|
||||
assert cfg.enabled is False
|
||||
assert cfg.text == ""
|
||||
|
||||
def test_empty_dict_returns_default(self):
|
||||
cfg = TextStickerConfig.from_dict({})
|
||||
assert cfg.text == ""
|
||||
|
||||
def test_not_dict_returns_default(self):
|
||||
cfg = TextStickerConfig.from_dict(123)
|
||||
assert cfg.text == ""
|
||||
|
||||
def test_text_content(self):
|
||||
cfg = TextStickerConfig.from_dict({"text": "Hello World"})
|
||||
assert cfg.text == "Hello World"
|
||||
|
||||
def test_font_size_minimum_1(self):
|
||||
cfg = TextStickerConfig.from_dict({"font_size": 0})
|
||||
assert cfg.font_size == 1
|
||||
|
||||
def test_font_size_normal(self):
|
||||
cfg = TextStickerConfig.from_dict({"font_size": 48})
|
||||
assert cfg.font_size == 48
|
||||
|
||||
def test_font_color(self):
|
||||
cfg = TextStickerConfig.from_dict({"font_color": "#00FF00"})
|
||||
assert cfg.font_color == "#00FF00"
|
||||
|
||||
def test_stroke_width_non_negative(self):
|
||||
cfg = TextStickerConfig.from_dict({"stroke_width": -2})
|
||||
assert cfg.stroke_width == 0
|
||||
|
||||
def test_stroke_width_normal(self):
|
||||
cfg = TextStickerConfig.from_dict({"stroke_width": 4})
|
||||
assert cfg.stroke_width == 4
|
||||
|
||||
def test_shadow_alpha_clamped(self):
|
||||
cfg = TextStickerConfig.from_dict({"shadow_alpha": 1.5})
|
||||
assert cfg.shadow_alpha == 1.0
|
||||
|
||||
def test_shadow_alpha_negative(self):
|
||||
cfg = TextStickerConfig.from_dict({"shadow_alpha": -0.5})
|
||||
assert cfg.shadow_alpha == 0.0
|
||||
|
||||
def test_shadow_offset(self):
|
||||
cfg = TextStickerConfig.from_dict({"shadow_x": 5, "shadow_y": 3})
|
||||
assert cfg.shadow_x == 5
|
||||
assert cfg.shadow_y == 3
|
||||
|
||||
def test_position_custom(self):
|
||||
cfg = TextStickerConfig.from_dict({"position": "top_right"})
|
||||
assert cfg.position == "top_right"
|
||||
|
||||
def test_custom_coordinates(self):
|
||||
cfg = TextStickerConfig.from_dict({"x": 10, "y": 20})
|
||||
assert cfg.x == 10.0
|
||||
assert cfg.y == 20.0
|
||||
|
||||
def test_start_time_non_negative(self):
|
||||
cfg = TextStickerConfig.from_dict({"start_time": -1.0})
|
||||
assert cfg.start_time == 0.0
|
||||
|
||||
def test_duration_non_negative(self):
|
||||
cfg = TextStickerConfig.from_dict({"duration": -2.0})
|
||||
assert cfg.duration == 0.0
|
||||
|
||||
def test_fade_in_out_non_negative(self):
|
||||
cfg = TextStickerConfig.from_dict({"fade_in": -1, "fade_out": -1})
|
||||
assert cfg.fade_in == 0.0
|
||||
assert cfg.fade_out == 0.0
|
||||
|
||||
def test_z_index_default(self):
|
||||
cfg = TextStickerConfig.from_dict({})
|
||||
assert cfg.z_index == 10
|
||||
|
||||
def test_bg_color(self):
|
||||
cfg = TextStickerConfig.from_dict({"bg_color": "#0000FF"})
|
||||
assert cfg.bg_color == "#0000FF"
|
||||
|
||||
def test_bg_padding_non_negative(self):
|
||||
cfg = TextStickerConfig.from_dict({"bg_padding": -5})
|
||||
assert cfg.bg_padding == 0
|
||||
|
||||
def test_bg_alpha_clamped(self):
|
||||
cfg = TextStickerConfig.from_dict({"bg_alpha": 2.0})
|
||||
assert cfg.bg_alpha == 1.0
|
||||
|
||||
def test_bg_corner_radius_non_negative(self):
|
||||
cfg = TextStickerConfig.from_dict({"bg_corner_radius": -3})
|
||||
assert cfg.bg_corner_radius == 0
|
||||
|
||||
def test_invalid_numeric_values_use_default(self):
|
||||
cfg = TextStickerConfig.from_dict({"font_size": "big"})
|
||||
assert cfg.font_size == 36 # 默认值
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StickerOverlayResult
|
||||
# ============================================================
|
||||
|
||||
|
||||
class TestStickerOverlayResult:
|
||||
def test_minimal_creation(self):
|
||||
r = StickerOverlayResult(filter_str="overlay=10:20", output_label="[out]")
|
||||
assert r.filter_str == "overlay=10:20"
|
||||
assert r.output_label == "[out]"
|
||||
assert r.extra_inputs == []
|
||||
|
||||
def test_with_extra_inputs(self):
|
||||
r = StickerOverlayResult(
|
||||
filter_str="overlay",
|
||||
output_label="[out]",
|
||||
extra_inputs=["img1.png", "img2.png"],
|
||||
)
|
||||
assert len(r.extra_inputs) == 2
|
||||
assert r.extra_inputs == ["img1.png", "img2.png"]
|
||||
|
||||
def test_extra_inputs_independent_lists(self):
|
||||
r1 = StickerOverlayResult(filter_str="a", output_label="[o1]")
|
||||
r2 = StickerOverlayResult(filter_str="b", output_label="[o2]")
|
||||
r1.extra_inputs.append("test.png")
|
||||
assert r2.extra_inputs == [] # 独立
|
||||
|
||||
|
||||
# ============================================================
|
||||
# resolve_sticker_position
|
||||
# ============================================================
|
||||
|
||||
|
||||
class TestResolveStickerPosition:
|
||||
CANVAS_W = 1920
|
||||
CANVAS_H = 1080
|
||||
|
||||
def test_preset_top_left(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"top_left",
|
||||
None,
|
||||
None,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
100,
|
||||
50,
|
||||
)
|
||||
# preset x=0.05, y=0.05 → 0.05*1920 - 50 = 96-50=46, 0.05*1080-25=54-25=29
|
||||
assert x == pytest.approx(0.05 * 1920 - 50)
|
||||
assert y == pytest.approx(0.05 * 1080 - 25)
|
||||
|
||||
def test_preset_center(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"center",
|
||||
None,
|
||||
None,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
200,
|
||||
100,
|
||||
)
|
||||
# center 0.5,0.5 → 贴纸左上角居中
|
||||
assert x == pytest.approx(1920 / 2 - 100)
|
||||
assert y == pytest.approx(1080 / 2 - 50)
|
||||
|
||||
def test_preset_bottom_right(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"bottom_right",
|
||||
None,
|
||||
None,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
100,
|
||||
50,
|
||||
)
|
||||
assert x == pytest.approx(0.95 * 1920 - 50)
|
||||
assert y == pytest.approx(0.95 * 1080 - 25)
|
||||
|
||||
def test_invalid_preset_defaults_center(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"invalid",
|
||||
None,
|
||||
None,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
100,
|
||||
50,
|
||||
)
|
||||
# 默认居中
|
||||
assert x == pytest.approx(1920 / 2 - 50)
|
||||
assert y == pytest.approx(1080 / 2 - 25)
|
||||
|
||||
def test_custom_percent_coordinates(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"top_left",
|
||||
30.0,
|
||||
70.0,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
# x=30% of 1920 = 576, y=70% of 1080 = 756
|
||||
assert x == pytest.approx(576.0)
|
||||
assert y == pytest.approx(756.0)
|
||||
|
||||
def test_custom_percent_clamped_0(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"center",
|
||||
-10.0,
|
||||
-5.0,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
assert x == 0.0
|
||||
assert y == 0.0
|
||||
|
||||
def test_custom_percent_clamped_100(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"center",
|
||||
150.0,
|
||||
120.0,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
assert x == pytest.approx(1920.0)
|
||||
assert y == pytest.approx(1080.0)
|
||||
|
||||
def test_custom_pixel_coordinates(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"center",
|
||||
500,
|
||||
300,
|
||||
"pixel",
|
||||
"pixel",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
assert x == pytest.approx(500.0)
|
||||
assert y == pytest.approx(300.0)
|
||||
|
||||
def test_x_only_override(self):
|
||||
# 只有x覆盖,y用预设
|
||||
x, y = resolve_sticker_position(
|
||||
"top_left",
|
||||
50.0,
|
||||
None,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
assert x == pytest.approx(0.5 * 1920) # 50%
|
||||
assert y == pytest.approx(0.05 * 1080) # 预设 top_left
|
||||
|
||||
def test_y_only_override(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"top_left",
|
||||
None,
|
||||
50.0,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
assert x == pytest.approx(0.05 * 1920)
|
||||
assert y == pytest.approx(0.5 * 1080)
|
||||
|
||||
def test_clamped_to_canvas_with_sticker_size(self):
|
||||
# 贴纸100x50,放在最右下角,不能超出画布
|
||||
x, y = resolve_sticker_position(
|
||||
"bottom_right",
|
||||
None,
|
||||
None,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
100,
|
||||
50,
|
||||
)
|
||||
assert x <= self.CANVAS_W - 100
|
||||
assert y <= self.CANVAS_H - 50
|
||||
|
||||
def test_clamped_left_top(self):
|
||||
# 很大的负偏移,被钳制在0
|
||||
x, y = resolve_sticker_position(
|
||||
"center",
|
||||
0.0,
|
||||
0.0,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
200,
|
||||
100,
|
||||
)
|
||||
# 0%位置 + 贴纸尺寸的一半偏移 = -100, -50 → 钳制到 0, 0
|
||||
assert x == 0
|
||||
assert y == 0
|
||||
|
||||
def test_zero_canvas_defaults_center(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"top_left",
|
||||
50,
|
||||
50,
|
||||
"pixel",
|
||||
"pixel",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
# canvas_w=0 → 回退到0.5 → 0*0.5=0
|
||||
assert x == 0.0
|
||||
assert y == 0.0
|
||||
|
||||
def test_sticker_size_zero(self):
|
||||
x, y = resolve_sticker_position(
|
||||
"center",
|
||||
None,
|
||||
None,
|
||||
"percent",
|
||||
"percent",
|
||||
self.CANVAS_W,
|
||||
self.CANVAS_H,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
assert x == pytest.approx(960.0)
|
||||
assert y == pytest.approx(540.0)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# parse_stickers_from_config
|
||||
# ============================================================
|
||||
|
||||
|
||||
class TestParseStickersFromConfig:
|
||||
def test_none_returns_empty(self):
|
||||
assert parse_stickers_from_config(None) == []
|
||||
|
||||
def test_empty_dict_returns_empty(self):
|
||||
assert parse_stickers_from_config({}) == []
|
||||
|
||||
def test_stickers_list(self):
|
||||
config = {"stickers": [{"type": "text", "text": "hi"}, {"type": "image", "image_url": "a.png"}]}
|
||||
result = parse_stickers_from_config(config)
|
||||
assert len(result) == 2
|
||||
assert result[0]["type"] == "text"
|
||||
|
||||
def test_stickers_empty_list(self):
|
||||
config = {"stickers": []}
|
||||
assert parse_stickers_from_config(config) == []
|
||||
|
||||
def test_stickers_not_list_returns_empty(self):
|
||||
config = {"stickers": "not_a_list"}
|
||||
assert parse_stickers_from_config(config) == []
|
||||
|
||||
def test_other_config_ignored(self):
|
||||
config = {"other_field": "value"}
|
||||
assert parse_stickers_from_config(config) == []
|
||||
|
||||
|
||||
# ============================================================
|
||||
# get_sticker_categories
|
||||
# ============================================================
|
||||
|
||||
|
||||
class TestGetStickerCategories:
|
||||
def test_returns_list(self):
|
||||
result = get_sticker_categories()
|
||||
assert isinstance(result, list)
|
||||
assert len(result) == len(STICKER_CATEGORIES)
|
||||
|
||||
def test_returns_copy(self):
|
||||
# 修改返回值不应影响常量
|
||||
result = get_sticker_categories()
|
||||
result.append(("new", "新分类"))
|
||||
assert len(STICKER_CATEGORIES) == len(STICKER_CATEGORIES)
|
||||
# 原常量不变
|
||||
assert ("new", "新分类") not in STICKER_CATEGORIES
|
||||
|
||||
def test_format(self):
|
||||
for cat in get_sticker_categories():
|
||||
assert len(cat) == 2
|
||||
assert isinstance(cat[0], str)
|
||||
assert isinstance(cat[1], str)
|
||||
Reference in New Issue
Block a user