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

1"""Tests for OptionSpec validation in lintro.tools.core.option_spec module.""" 

2 

3from __future__ import annotations 

4 

5import pytest 

6from assertpy import assert_that 

7 

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) 

18 

19 

20def test_bool_option_validates_true() -> None: 

21 """Bool option accepts True value.""" 

22 spec = bool_option("preview", "--preview") 

23 spec.validate(True) 

24 

25 

26def test_bool_option_validates_false() -> None: 

27 """Bool option accepts False value.""" 

28 spec = bool_option("preview", "--preview") 

29 spec.validate(False) 

30 

31 

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") 

37 

38 

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"]) 

43 

44 

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([]) 

49 

50 

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) 

55 

56 

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) 

62 

63 

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) 

69 

70 

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) 

76 

77 

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") 

83 

84 

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") 

90 

91 

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"]) 

97 

98 

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") 

104 

105 

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) 

116 

117 

118def test_optional_option_accepts_none() -> None: 

119 """Optional option accepts None value.""" 

120 spec = str_option("optional", "--optional") 

121 spec.validate(None)