Files
acorderob-sd-webui-prompt-p…/.github/instructions/tests.instructions.md
T
Antonio Cordero BalcazarandCopilot 04119b169e * Improved combinatorial limit warning.
* Added combinatorial shuffle.
* A1111: Improved combinatorial with hiresfix.
* Some refactoring.
* Update of AI test instructions.

Co-authored-by: Copilot <copilot@github.com>
2026-05-02 13:40:06 +02:00

4.4 KiB

description, applyTo
description applyTo
Use when writing, editing, or reviewing test files. Enforces unittest patterns used in this project: TestCase inheritance, base class setup, process() helper, and naming conventions. tests/**/*.py

Test Conventions

All tests use the standard unittest module. Do not use pytest-specific features (fixtures, @pytest.mark, conftest.py, etc.).

File & Class Naming

  • One test file per concern, named tests_{category}.py
  • One test class per file inheriting from TestPromptPostProcessorBase:
import unittest
from tests.base_tests import TestPromptPostProcessorBase

class TestMyFeature(TestPromptPostProcessorBase):

    def setUp(self):
        super().setUp(enable_file_logging=False)

Test Method Naming

test_{2-3 letter category prefix}_{short_description}

Examples: test_cl_simple, test_ch_choices, test_wc_ignore

Running a Test Case via self.process()

Use the process() helper from the base class — never instantiate PromptPostProcessor directly in test methods unless there is a need to pass specific options not covered by the default setup or the "nocup" or "nostrict" options.

def test_cl_simple(self):
    """simple cleanup"""
    self.process(
        InputTuple(
            "input prompt",                         # positive prompt
            ""),                                    # negative prompt
        OutputTuple(
            "expected output",                      # expected positive prompt
            "",                                     # expected negative prompt
            {}                                      # expected variables (optional)
        ),
    )

def test_cl_combinatorial(self):
    """simple cleanup"""
    self.process(
        InputTuple(
            "input prompt",                         # positive prompt
            ""),                                    # negative prompt
        [
            OutputTuple(
                "expected output",                  # expected positive prompt
                "",                                 # expected negative prompt
                {}                                  # expected variables (optional)
            ),
            OutputTuple(
                "expected output",                  # expected positive prompt
                "",                                 # expected negative prompt
                {}                                  # expected variables (optional)
            ),
        ],
        combinatorial=True,
    )

process() Signature (key parameters)

Parameter Type Notes
input_prompts InputTuple Prompts input
expected_output OutputTuple | list[OutputTuple] Single or multiple valid outputs
seed int Optional, defaults to fixed seed
ppp PromptPostProcessor | str | None Supported values "nocup", "nostrict" or a specific instance
interrupted bool Expected interrupt flag
combinatorial bool Whether to run a combinatorial generation. If a specific ppp instance is used then it is ignored

Assertions

Use assertEqual or similar methods with a descriptive message string:

self.assertEqual(result, expected, "Descriptive failure message")
self.assertIn(key, container, f"Key '{key}' not found in output")

Do not use bare assert statements.

Default Options & Environment

Override self.defopts or self.def_env_info to pass non-default options — do not hardcode option dicts from scratch:

def test_cl_custom(self):
    """cleanup with custom separator"""
    self.process(
        InputTuple("a, , b", ""),
        OutputTuple("a | b", ""),
        ppp=PromptPostProcessor(
            self.ppp_logger,
            self.def_env_info,
            replace(
                self.defopts,
                keep_choices_order=True,
                cup_do_cleanup=False,
                do_combinatorial=True,
            ),
            self.grammar_content,
            self.interrupt,
            self.wildcards_obj,
            self.extranetwork_maps_obj,
        ),
    )

Entry Point

Every test file must start with:

if __name__ == "__main__":
    raise SystemExit("This script must not be run directly")