Files
kunail0804-ComfyUI-Scene-Co…/tests/resolver/test_resolver_node.py
T
72d6bfdcf4 feat(nodes): add the Resolver ComfyUI node (#21) (#65)
Add nodes/resolver_node.py: ResolverNode, a thin adapter that delegates to
resolve_scene (MASTER_SPEC §20).

- Required inputs scene (SCENE model) and knowledge_base (KNOWLEDGE_BASE, from
  the loader node); optional config (COMPILER_CONFIG) defaulting to Config().
- Outputs (resolved_tags, warnings, errors): RESOLVED_TAGS plus surfaced
  diagnostics. No compiler logic in the node.
- Registered as SceneCompilerResolver ("Resolver").

Tests: metadata/inputs, real resolution over a small in-memory Knowledge Base,
delegation + message surfacing (monkeypatched), default config, registration.

Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 14:13:37 +02:00

90 lines
2.9 KiB
Python

"""Tests for the Resolver ComfyUI node (issue #21). No Ollama."""
from __future__ import annotations
import nodes
import nodes.resolver_node as node_module
from compiler.common.config import Config
from compiler.common.knowledge_base import KnowledgeBase, KnowledgeBaseEntry
from compiler.common.message_codes import message
from compiler.common.result import CompilerResult
from nodes.resolver_node import ResolverNode
from schemas.models import Scene
def kb() -> KnowledgeBase:
return KnowledgeBase(
[
KnowledgeBaseEntry(
id="female", tags=("1girl",), category="character", aliases=("girl",)
),
KnowledgeBaseEntry(id="long_hair", tags=("long hair",), category="hair"),
]
)
def scene() -> Scene:
return Scene.from_json(
{
"characters": [
{
"id": 0,
"identity": ["girl"],
"appearance": ["long hair"],
"clothing": [],
"accessories": [],
"pose": [],
"expression": [],
"actions": [],
}
],
"interactions": [],
"objects": [],
"environment": [],
"camera": [],
"lighting": [],
"metadata": {"schema_version": "1.0"},
}
)
def test_node_metadata() -> None:
assert ResolverNode.RETURN_TYPES == ("RESOLVED_TAGS", "STRING", "STRING")
assert ResolverNode.RETURN_NAMES == ("resolved_tags", "warnings", "errors")
inputs = ResolverNode.INPUT_TYPES()
assert set(inputs["required"]) == {"scene", "knowledge_base"}
assert "config" in inputs["optional"]
def test_resolves_tags_with_real_resolver() -> None:
resolved, warnings, errors = ResolverNode().run(scene(), kb())
assert [t.tag for t in resolved] == ["1girl", "long hair"]
assert errors == ""
def test_delegates_and_surfaces_messages(monkeypatch) -> None:
def fake_resolve(scene_arg, knowledge_base, config):
return CompilerResult(data=()).add_warning(message("SC0001", "unknown 'x'"))
monkeypatch.setattr(node_module, "resolve_scene", fake_resolve)
resolved, warnings, errors = ResolverNode().run(scene(), kb())
assert resolved == ()
assert "SC0001: unknown 'x'" in warnings
def test_default_config_used_when_absent(monkeypatch) -> None:
captured = {}
def fake_resolve(scene_arg, knowledge_base, config):
captured["config"] = config
return CompilerResult(data=())
monkeypatch.setattr(node_module, "resolve_scene", fake_resolve)
ResolverNode().run(scene(), kb())
assert isinstance(captured["config"], Config)
def test_registered_for_comfyui() -> None:
assert nodes.NODE_CLASS_MAPPINGS["SceneCompilerResolver"] is ResolverNode
assert nodes.NODE_DISPLAY_NAME_MAPPINGS["SceneCompilerResolver"] == "Resolver"