"""Tests for ModelsSamplingNode.""" import json import struct import pytest from mp_nodes.models_sampling import ModelsSamplingNode def run(mode, **kwargs): return ModelsSamplingNode().process(mode=mode, theme="(use pack default)", **kwargs) def _make_safetensors(tmp_path, name, metadata=None, tensor_keys=None): """Create a minimal valid safetensors file with the given metadata block.""" header = {} if metadata is not None: header["__metadata__"] = metadata for k in tensor_keys or []: header[k] = {"dtype": "F32", "shape": [1], "data_offsets": [0, 4]} header_bytes = json.dumps(header).encode("utf-8") # Pad to 8-byte alignment pad = (8 - len(header_bytes) % 8) % 8 header_bytes += b" " * pad body = b"\x00\x00\x00\x00" * len(tensor_keys or []) path = tmp_path / name with open(path, "wb") as f: f.write(struct.pack("= 2 assert info["history"][-1] == 2 class TestSampling: def test_sampler_pick(self): assert run("sampler_pick", sampler="euler")[4] == "euler" def test_scheduler_pick(self): assert run("scheduler_pick", scheduler="karras")[3] == "karras" def test_sampler_params_bundle(self): out = run("sampler_params_bundle", sampler="dpmpp_2m", scheduler="karras", steps=30, cfg=8.0, denoise=0.8) assert out[7] == 8.0 # cfg as FLOAT bundle = out[8] assert bundle["sampler"] == "dpmpp_2m" assert bundle["scheduler"] == "karras" assert bundle["steps"] == 30 assert bundle["denoise"] == 0.8 class TestOpaqueOutputs: """ModelsSamplingNode has MODEL/CLIP/VAE in RETURN_TYPES. None of our ops fill them. Verify they pad to None (not raise).""" def test_unfilled_opaque_outputs_are_none(self): out = run("sampler_pick", sampler="euler") # MODEL/CLIP/VAE are at indices 0, 1, 2 assert out[0] is None assert out[1] is None assert out[2] is None class TestModelResolution: def test_qwen_image_16_9(self): out = run("model_resolution_pick", model_preset="Qwen-Image — 16:9 1664x928") assert (out[5], out[6]) == (1664, 928) assert out[8]["preset"] == "Qwen-Image — 16:9 1664x928" def test_sd15_native(self): out = run("model_resolution_pick", model_preset="SD 1.5 — 512x512") assert (out[5], out[6]) == (512, 512) def test_wan_5b_portrait(self): out = run("model_resolution_pick", model_preset="Wan 2.2 TI2V-5B — 720P portrait 704x1280") assert (out[5], out[6]) == (704, 1280) def test_widget_appended_last_and_does_not_shadow_aspect_ratio_preset(self): optional = ModelsSamplingNode.INPUT_TYPES()["optional"] assert list(optional)[-1] == "model_preset" assert "16:9" in optional["preset"][0] def test_every_preset_dimension_is_positive(self): from mp_nodes.models_sampling.operations.model_resolution import _MODEL_RESOLUTIONS assert all(w > 0 and h > 0 for w, h in _MODEL_RESOLUTIONS.values()) class TestSamplerLists: def test_samplers_include_current_core_names(self): from mp_nodes.models_sampling.operations.seed_sampling import _SAMPLERS for name in ("euler_cfg_pp", "res_multistep", "er_sde", "sa_solver", "cfgpp_ud10_ab", "uni_pc_bh2"): assert name in _SAMPLERS assert len(_SAMPLERS) == len(set(_SAMPLERS)) def test_schedulers_include_current_core_names(self): from mp_nodes.models_sampling.operations.seed_sampling import _SCHEDULERS assert "linear_quadratic" in _SCHEDULERS and "kl_optimal" in _SCHEDULERS def test_new_scheduler_passes_through(self): assert run("scheduler_pick", scheduler="kl_optimal")[3] == "kl_optimal"