11import dataclasses
22from copy import deepcopy
33from pathlib import Path
4- from unittest .mock import patch
4+ from typing import NoReturn
5+ from unittest .mock import Mock , patch
56
67import pytest
78from tomlkit import TOMLDocument , dumps , parse
8- from twyn .base .constants import DEFAULT_PROJECT_TOML_FILE , DEFAULT_TOP_PYPI_PACKAGES , AvailableLoggingLevels
9+ from twyn .base .constants import (
10+ DEFAULT_PROJECT_TOML_FILE ,
11+ DEFAULT_TOP_PYPI_PACKAGES ,
12+ DEFAULT_TWYN_TOML_FILE ,
13+ AvailableLoggingLevels ,
14+ )
915from twyn .config .config_handler import ConfigHandler , ReadTwynConfiguration , TwynConfiguration
1016from twyn .config .exceptions import (
1117 AllowlistPackageAlreadyExistsError ,
1622from twyn .file_handler .exceptions import PathNotFoundError
1723from twyn .file_handler .file_handler import FileHandler
1824
25+ from tests .conftest import create_tmp_file
26+
1927
20- class TestConfig :
21- def throw_exception (self ):
28+ class TestConfigHandler :
29+ def throw_exception (self ) -> NoReturn :
2230 raise PathNotFoundError
2331
2432 @patch ("twyn.file_handler.file_handler.FileHandler.read" )
25- def test_enforce_file_error (self , mock_is_file ) :
33+ def test_enforce_file_error (self , mock_is_file : Mock ) -> None :
2634 mock_is_file .side_effect = self .throw_exception
2735 with pytest .raises (TOMLError ):
2836 ConfigHandler (FileHandler (DEFAULT_PROJECT_TOML_FILE ), enforce_file = True ).resolve_config ()
2937
3038 @patch ("twyn.file_handler.file_handler.FileHandler.read" )
31- def test_no_enforce_file_on_non_existent_file (self , mock_is_file ) :
39+ def test_no_enforce_file_on_non_existent_file (self , mock_is_file : Mock ) -> None :
3240 """Resolving the config without enforcing the file to be present gives you defaults."""
3341 mock_is_file .side_effect = self .throw_exception
3442 config = ConfigHandler (FileHandler (DEFAULT_PROJECT_TOML_FILE ), enforce_file = False ).resolve_config ()
@@ -39,20 +47,22 @@ def test_no_enforce_file_on_non_existent_file(self, mock_is_file):
3947 logging_level = AvailableLoggingLevels .warning ,
4048 allowlist = set (),
4149 pypi_reference = DEFAULT_TOP_PYPI_PACKAGES ,
50+ use_cache = True ,
4251 )
4352
44- def test_config_raises_for_unknown_file (self ):
53+ def test_config_raises_for_unknown_file (self ) -> None :
4554 with pytest .raises (TOMLError ):
4655 ConfigHandler (FileHandler ("non-existent-file.toml" )).resolve_config ()
4756
48- def test_read_config_values (self , pyproject_toml_file ) :
57+ def test_read_config_values (self , pyproject_toml_file : Path ) -> None :
4958 config = ConfigHandler (file_handler = FileHandler (pyproject_toml_file )).resolve_config ()
5059 assert config .dependency_file == "my_file.txt"
5160 assert config .selector_method == "all"
5261 assert config .logging_level == AvailableLoggingLevels .debug
5362 assert config .allowlist == {"boto4" , "boto2" }
63+ assert config .use_cache is False
5464
55- def test_get_twyn_data_from_file (self , pyproject_toml_file ) :
65+ def test_get_twyn_data_from_file (self , pyproject_toml_file : Path ) -> None :
5666 handler = ConfigHandler (FileHandler (str (pyproject_toml_file )))
5767
5868 toml = handler ._read_toml ()
@@ -63,9 +73,10 @@ def test_get_twyn_data_from_file(self, pyproject_toml_file):
6373 logging_level = "debug" ,
6474 allowlist = {"boto4" , "boto2" },
6575 pypi_reference = None ,
76+ use_cache = False ,
6677 )
6778
68- def test_write_toml (self , pyproject_toml_file ) :
79+ def test_write_toml (self , pyproject_toml_file : Path ) -> None :
6980 handler = ConfigHandler (FileHandler (pyproject_toml_file ))
7081 toml = handler ._read_toml ()
7182
@@ -101,15 +112,40 @@ def test_write_toml(self, pyproject_toml_file):
101112 "logging_level" : "debug" ,
102113 "allowlist" : {},
103114 "pypi_reference" : DEFAULT_TOP_PYPI_PACKAGES ,
115+ "use_cache" : False ,
104116 },
105117 }
106118 }
107119
120+ def test_get_default_config_file_path_twyn_file_exists (self , tmp_path : Path , pyproject_toml_file : Path ) -> None :
121+ assert pyproject_toml_file .exists ()
122+ twyn_path = tmp_path / DEFAULT_TWYN_TOML_FILE
123+ with (
124+ create_tmp_file (twyn_path , "" ),
125+ patch ("twyn.config.config_handler.DEFAULT_TWYN_TOML_FILE" , new = str (twyn_path )),
126+ patch ("twyn.config.config_handler.DEFAULT_PROJECT_TOML_FILE" , new = str (pyproject_toml_file )),
127+ ):
128+ assert twyn_path .exists ()
129+
130+ assert ConfigHandler .get_default_config_file_path () == str (twyn_path )
131+
132+ def test_get_default_config_file_path_twyn_file_does_not_exist (
133+ self , tmp_path : Path , pyproject_toml_file : Path
134+ ) -> None :
135+ assert pyproject_toml_file .exists ()
136+ twyn_path = tmp_path / DEFAULT_TWYN_TOML_FILE
137+ with (
138+ patch ("twyn.config.config_handler.DEFAULT_TWYN_TOML_FILE" , new = str (twyn_path )),
139+ patch ("twyn.config.config_handler.DEFAULT_PROJECT_TOML_FILE" , new = str (pyproject_toml_file )),
140+ ):
141+ assert not twyn_path .exists ()
142+ assert ConfigHandler .get_default_config_file_path () == str (pyproject_toml_file )
143+
108144
109145class TestAllowlistConfigHandler :
110146 @patch ("twyn.file_handler.file_handler.FileHandler.write" )
111147 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
112- def test_allowlist_add (self , mock_toml , mock_write_toml ) :
148+ def test_allowlist_add (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
113149 mock_toml .return_value = TOMLDocument ()
114150
115151 config = ConfigHandler (FileHandler ("some-file" ))
@@ -123,7 +159,7 @@ def test_allowlist_add(self, mock_toml, mock_write_toml):
123159
124160 @patch ("twyn.config.config_handler.ConfigHandler._write_toml" )
125161 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
126- def test_allowlist_add_duplicate_error (self , mock_toml , mock_write_toml ) :
162+ def test_allowlist_add_duplicate_error (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
127163 mock_toml .return_value = parse (dumps ({"tool" : {"twyn" : {"allowlist" : ["mypackage" ]}}}))
128164
129165 config = ConfigHandler (FileHandler ("some-file" ))
@@ -137,7 +173,7 @@ def test_allowlist_add_duplicate_error(self, mock_toml, mock_write_toml):
137173
138174 @patch ("twyn.config.config_handler.ConfigHandler._write_toml" )
139175 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
140- def test_allowlist_remove_completely (self , mock_toml , mock_write_toml ) :
176+ def test_allowlist_remove_completely (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
141177 mock_toml .return_value = parse (dumps ({"tool" : {"twyn" : {"allowlist" : ["mypackage" ]}}}))
142178
143179 config = ConfigHandler (FileHandler ("some-file" ))
@@ -147,7 +183,7 @@ def test_allowlist_remove_completely(self, mock_toml, mock_write_toml):
147183
148184 @patch ("twyn.config.config_handler.ConfigHandler._write_toml" )
149185 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
150- def test_allowlist_remove (self , mock_toml , mock_write_toml ) :
186+ def test_allowlist_remove (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
151187 mock_toml .return_value = parse (dumps ({"tool" : {"twyn" : {"allowlist" : ["mypackage" , "another-package" ]}}}))
152188
153189 config = ConfigHandler (FileHandler ("some-file" ))
@@ -157,7 +193,7 @@ def test_allowlist_remove(self, mock_toml, mock_write_toml):
157193
158194 @patch ("twyn.config.config_handler.ConfigHandler._write_toml" )
159195 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
160- def test_allowlist_remove_non_existent_package_error (self , mock_toml , mock_write_toml ) :
196+ def test_allowlist_remove_non_existent_package_error (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
161197 mock_toml .return_value = parse (dumps ({"tool" : {"twyn" : {"allowlist" : ["mypackage" ]}}}))
162198
163199 config = ConfigHandler (FileHandler ("some-file" ))
@@ -170,7 +206,7 @@ def test_allowlist_remove_non_existent_package_error(self, mock_toml, mock_write
170206 assert not mock_write_toml .called
171207
172208 @pytest .mark .parametrize ("valid_selector" , ["first-letter" , "nearby-letter" , "all" ])
173- def test_valid_selector_methods_accepted (self , valid_selector : str , tmp_path : Path ):
209+ def test_valid_selector_methods_accepted (self , valid_selector : str , tmp_path : Path ) -> None :
174210 """Test that all valid selector methods are accepted."""
175211 pyproject_toml = tmp_path / "pyproject.toml"
176212 pyproject_toml .write_text ("" )
@@ -180,7 +216,7 @@ def test_valid_selector_methods_accepted(self, valid_selector: str, tmp_path: Pa
180216 resolved_config = config .resolve_config (selector_method = valid_selector )
181217 assert resolved_config .selector_method == valid_selector
182218
183- def test_invalid_selector_method_rejected (self , tmp_path : Path ):
219+ def test_invalid_selector_method_rejected (self , tmp_path : Path ) -> None :
184220 """Test that invalid selector methods are rejected with appropriate error."""
185221 pyproject_toml = tmp_path / "pyproject.toml"
186222 pyproject_toml .write_text ("" )
@@ -193,7 +229,7 @@ def test_invalid_selector_method_rejected(self, tmp_path: Path):
193229 assert "Invalid selector_method 'random-selector'" in error_message
194230 assert "Must be one of: all, first-letter, nearby-letter" in error_message
195231
196- def test_invalid_selector_method_from_config_file (self , tmp_path : Path ):
232+ def test_invalid_selector_method_from_config_file (self , tmp_path : Path ) -> None :
197233 """Test that invalid selector method from config file is rejected."""
198234 # Create a config file with invalid selector method
199235 pyproject_toml = tmp_path / "pyproject.toml"
0 commit comments