Files
JakoError-random_resolution…/test_random_resolution_picker.py

200 lines
7.3 KiB
Python

import math
import pytest
from random_resolution_picker.random_resolution_picker import (
_parse_resolutions,
RandomResolutionPicker,
)
# ---------------------------------------------------------------------------
# _parse_resolutions — valid input
# ---------------------------------------------------------------------------
def test_parse_basic():
assert _parse_resolutions("1328,1328\n1664,928") == [(1328, 1328), (1664, 928)]
def test_parse_skips_blank_lines():
assert _parse_resolutions("\n1328,1328\n\n928,1664\n") == [(1328, 1328), (928, 1664)]
def test_parse_skips_comment_lines():
assert _parse_resolutions("# square\n1328,1328") == [(1328, 1328)]
def test_parse_strips_surrounding_whitespace():
assert _parse_resolutions(" 1328 , 1328 ") == [(1328, 1328)]
def test_parse_duplicate_lines_kept_as_weighted_entries():
# Duplicates are intentional — they increase selection probability.
result = _parse_resolutions("512,512\n512,512\n1024,1024")
assert result == [(512, 512), (512, 512), (1024, 1024)]
# ---------------------------------------------------------------------------
# _parse_resolutions — invalid input
# ---------------------------------------------------------------------------
def test_parse_raises_missing_comma_includes_line_number():
with pytest.raises(ValueError, match=r"Line 2:.*exactly one comma"):
_parse_resolutions("# ok\n1328")
def test_parse_raises_too_many_commas_includes_line_number():
with pytest.raises(ValueError, match=r"Line 1:.*exactly one comma"):
_parse_resolutions("1328,928,64")
def test_parse_raises_non_integer_width_includes_line_number():
with pytest.raises(ValueError, match=r"Line 3:.*integers"):
_parse_resolutions("512,512\n1024,1024\nabc,512")
def test_parse_raises_non_integer_height_includes_line_number():
with pytest.raises(ValueError, match=r"Line 1:.*integers"):
_parse_resolutions("512,abc")
def test_parse_raises_zero_width_includes_line_number():
with pytest.raises(ValueError, match=r"Line 2:.*positive"):
_parse_resolutions("512,512\n0,1328")
def test_parse_raises_zero_height_includes_line_number():
with pytest.raises(ValueError, match=r"Line 1:.*positive"):
_parse_resolutions("512,0")
def test_parse_raises_negative_value_includes_line_number():
with pytest.raises(ValueError, match=r"Line 1:.*positive"):
_parse_resolutions("-512,1024")
def test_parse_raises_empty_list_all_comments():
with pytest.raises(ValueError, match="empty"):
_parse_resolutions("# comment only\n\n")
def test_parse_raises_empty_string():
with pytest.raises(ValueError, match="empty"):
_parse_resolutions("")
def test_parse_raises_whitespace_only():
with pytest.raises(ValueError, match="empty"):
_parse_resolutions(" \n\t\n ")
# ---------------------------------------------------------------------------
# RandomResolutionPicker.pick — determinism and output shape
# ---------------------------------------------------------------------------
def test_pick_same_seed_returns_same_result():
node = RandomResolutionPicker()
r1 = node.pick("1328,1328\n1664,928", auto_randomize=False, seed=42)
r2 = node.pick("1328,1328\n1664,928", auto_randomize=False, seed=42)
assert r1 == r2
def test_pick_different_seeds_can_return_different_results():
node = RandomResolutionPicker()
# With a two-entry list, seeds 0 and 1 should diverge eventually.
results = {
node.pick("1328,1328\n1664,928", auto_randomize=False, seed=s)[:2]
for s in range(20)
}
assert len(results) > 1, "20 different seeds all produced the same pair — suspicious"
def test_pick_result_is_always_from_the_list():
node = RandomResolutionPicker()
valid = {(1328, 1328), (1664, 928), (928, 1664)}
for seed in range(50):
w, h, label = node.pick("1328,1328\n1664,928\n928,1664", auto_randomize=False, seed=seed)
assert (w, h) in valid
assert label == f"{w}x{h}"
def test_pick_single_entry_always_returns_it():
node = RandomResolutionPicker()
for seed in range(10):
w, h, _ = node.pick("512,768", auto_randomize=False, seed=seed)
assert (w, h) == (512, 768)
def test_pick_label_format():
node = RandomResolutionPicker()
w, h, label = node.pick("1024,768", auto_randomize=False, seed=0)
assert label == "1024x768"
# ---------------------------------------------------------------------------
# IS_CHANGED — cache invalidation contract
# ---------------------------------------------------------------------------
def test_is_changed_returns_nan_when_auto_randomize():
result = RandomResolutionPicker.IS_CHANGED("1328,1328", auto_randomize=True, seed=0)
assert math.isnan(result), "auto_randomize=True must return NaN to force re-execution"
def test_is_changed_returns_equal_value_for_same_inputs():
r1 = RandomResolutionPicker.IS_CHANGED("1328,1328", auto_randomize=False, seed=5)
r2 = RandomResolutionPicker.IS_CHANGED("1328,1328", auto_randomize=False, seed=5)
assert r1 == r2
def test_is_changed_differs_when_seed_changes():
r1 = RandomResolutionPicker.IS_CHANGED("1328,1328", auto_randomize=False, seed=5)
r2 = RandomResolutionPicker.IS_CHANGED("1328,1328", auto_randomize=False, seed=6)
assert r1 != r2
def test_is_changed_differs_when_resolutions_text_changes():
r1 = RandomResolutionPicker.IS_CHANGED("1328,1328", auto_randomize=False, seed=5)
r2 = RandomResolutionPicker.IS_CHANGED("1664,928", auto_randomize=False, seed=5)
assert r1 != r2
def test_is_changed_auto_randomize_false_is_not_nan():
result = RandomResolutionPicker.IS_CHANGED("1328,1328", auto_randomize=False, seed=0)
assert result == ("1328,1328", 0)
# ---------------------------------------------------------------------------
# extra_pnginfo — metadata embedding
# ---------------------------------------------------------------------------
def test_pick_writes_metadata_to_extra_pnginfo():
node = RandomResolutionPicker()
meta = {}
w, h, label = node.pick("512,768", auto_randomize=False, seed=0, extra_pnginfo=meta)
assert "RandomResolutionPicker" in meta
data = meta["RandomResolutionPicker"]
assert data["resolution"] == label
assert data["resolution_width"] == w
assert data["resolution_height"] == h
assert data["resolution_seed"] == 0
def test_pick_extra_pnginfo_none_does_not_raise():
node = RandomResolutionPicker()
# Must not raise even when ComfyUI passes None (no Save Image node downstream).
node.pick("512,768", auto_randomize=False, seed=0, extra_pnginfo=None)
def test_pick_extra_pnginfo_non_dict_does_not_raise():
node = RandomResolutionPicker()
# ComfyUI may pass unexpected types; guard must be isinstance check, not truthiness.
node.pick("512,768", auto_randomize=False, seed=0, extra_pnginfo="unexpected")
def test_pick_auto_randomize_true_picks_from_list_and_records_seed():
node = RandomResolutionPicker()
from random_resolution_picker.random_resolution_picker import MAX_SEED
meta = {}
w, h, label = node.pick("512,768\n1024,1024", auto_randomize=True, seed=0, extra_pnginfo=meta)
assert (w, h) in {(512, 768), (1024, 1024)}
assert label == f"{w}x{h}"
assert 0 <= meta["RandomResolutionPicker"]["resolution_seed"] <= MAX_SEED