Coverage for tests / unit / tools / core / test_option_spec.py: 100%
58 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Tests for OptionSpec validation in lintro.tools.core.option_spec module."""
3from __future__ import annotations
5import pytest
6from assertpy import assert_that
8from lintro.tools.core.option_spec import (
9 OptionSpec,
10 OptionType,
11 bool_option,
12 enum_option,
13 int_option,
14 list_option,
15 positive_int_option,
16 str_option,
17)
20def test_bool_option_validates_true() -> None:
21 """Bool option accepts True value."""
22 spec = bool_option("preview", "--preview")
23 spec.validate(True)
26def test_bool_option_validates_false() -> None:
27 """Bool option accepts False value."""
28 spec = bool_option("preview", "--preview")
29 spec.validate(False)
32def test_bool_option_rejects_non_bool() -> None:
33 """Bool option rejects non-boolean values."""
34 spec = bool_option("preview", "--preview")
35 with pytest.raises(ValueError, match="preview"):
36 spec.validate("not a bool")
39def test_bool_option_to_cli_args_true() -> None:
40 """Bool option converts True to CLI flag."""
41 spec = bool_option("preview", "--preview")
42 assert_that(spec.to_cli_args(True)).is_equal_to(["--preview"])
45def test_bool_option_to_cli_args_false() -> None:
46 """Bool option converts False to empty list."""
47 spec = bool_option("preview", "--preview")
48 assert_that(spec.to_cli_args(False)).is_equal_to([])
51def test_int_option_validates_valid_int() -> None:
52 """Int option accepts valid integer."""
53 spec = int_option("line_length", "--line-length", min_value=1, max_value=200)
54 spec.validate(88)
57def test_int_option_rejects_below_min() -> None:
58 """Int option rejects value below minimum."""
59 spec = int_option("line_length", "--line-length", min_value=1, max_value=200)
60 with pytest.raises(ValueError, match="line_length"):
61 spec.validate(0)
64def test_int_option_rejects_above_max() -> None:
65 """Int option rejects value above maximum."""
66 spec = int_option("line_length", "--line-length", min_value=1, max_value=200)
67 with pytest.raises(ValueError, match="line_length"):
68 spec.validate(201)
71def test_positive_int_option_rejects_zero() -> None:
72 """Positive int option rejects zero."""
73 spec = positive_int_option("timeout", "--timeout")
74 with pytest.raises(ValueError, match="timeout"):
75 spec.validate(0)
78def test_str_option_with_choices_rejects_invalid() -> None:
79 """Str option with choices rejects invalid choice."""
80 spec = str_option("target", "--target", choices=["py38", "py311"])
81 with pytest.raises(ValueError, match="target must be one of"):
82 spec.validate("py37")
85def test_list_option_rejects_non_list() -> None:
86 """List option rejects non-list values."""
87 spec = list_option("ignore", "--ignore")
88 with pytest.raises(ValueError, match="ignore"):
89 spec.validate("not a list")
92def test_list_option_to_cli_args() -> None:
93 """List option converts each item to CLI args."""
94 spec = list_option("ignore", "--ignore")
95 result = spec.to_cli_args(["E501", "W503"])
96 assert_that(result).is_equal_to(["--ignore", "E501", "--ignore", "W503"])
99def test_enum_option_rejects_invalid_choice() -> None:
100 """Enum option rejects invalid choice."""
101 spec = enum_option("severity", "--severity", choices=["error", "warning"])
102 with pytest.raises(ValueError, match="severity must be one of"):
103 spec.validate("info")
106def test_required_option_validates_none() -> None:
107 """Required option raises on None value."""
108 spec: OptionSpec[str] = OptionSpec(
109 name="required_opt",
110 cli_flag="--required",
111 option_type=OptionType.STR,
112 required=True,
113 )
114 with pytest.raises(ValueError, match="required_opt is required"):
115 spec.validate(None)
118def test_optional_option_accepts_none() -> None:
119 """Optional option accepts None value."""
120 spec = str_option("optional", "--optional")
121 spec.validate(None)