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 ()
@@ -41,18 +49,18 @@ def test_no_enforce_file_on_non_existent_file(self, mock_is_file):
4149 pypi_reference = DEFAULT_TOP_PYPI_PACKAGES ,
4250 )
4351
44- def test_config_raises_for_unknown_file (self ):
52+ def test_config_raises_for_unknown_file (self ) -> None :
4553 with pytest .raises (TOMLError ):
4654 ConfigHandler (FileHandler ("non-existent-file.toml" )).resolve_config ()
4755
48- def test_read_config_values (self , pyproject_toml_file ) :
56+ def test_read_config_values (self , pyproject_toml_file : Path ) -> None :
4957 config = ConfigHandler (file_handler = FileHandler (pyproject_toml_file )).resolve_config ()
5058 assert config .dependency_file == "my_file.txt"
5159 assert config .selector_method == "all"
5260 assert config .logging_level == AvailableLoggingLevels .debug
5361 assert config .allowlist == {"boto4" , "boto2" }
5462
55- def test_get_twyn_data_from_file (self , pyproject_toml_file ) :
63+ def test_get_twyn_data_from_file (self , pyproject_toml_file : Path ) -> None :
5664 handler = ConfigHandler (FileHandler (str (pyproject_toml_file )))
5765
5866 toml = handler ._read_toml ()
@@ -65,7 +73,7 @@ def test_get_twyn_data_from_file(self, pyproject_toml_file):
6573 pypi_reference = None ,
6674 )
6775
68- def test_write_toml (self , pyproject_toml_file ) :
76+ def test_write_toml (self , pyproject_toml_file : Path ) -> None :
6977 handler = ConfigHandler (FileHandler (pyproject_toml_file ))
7078 toml = handler ._read_toml ()
7179
@@ -105,11 +113,35 @@ def test_write_toml(self, pyproject_toml_file):
105113 }
106114 }
107115
116+ def test_get_default_config_file_path_twyn_file_exists (self , tmp_path : Path , pyproject_toml_file : Path ) -> None :
117+ assert pyproject_toml_file .exists ()
118+ twyn_path = tmp_path / DEFAULT_TWYN_TOML_FILE
119+ with (
120+ create_tmp_file (twyn_path , "" ),
121+ patch ("twyn.config.config_handler.DEFAULT_TWYN_TOML_FILE" , new = str (twyn_path )),
122+ patch ("twyn.config.config_handler.DEFAULT_PROJECT_TOML_FILE" , new = str (pyproject_toml_file )),
123+ ):
124+ assert twyn_path .exists ()
125+
126+ assert ConfigHandler .get_default_config_file_path () == str (twyn_path )
127+
128+ def test_get_default_config_file_path_twyn_file_does_not_exist (
129+ self , tmp_path : Path , pyproject_toml_file : Path
130+ ) -> None :
131+ assert pyproject_toml_file .exists ()
132+ twyn_path = tmp_path / DEFAULT_TWYN_TOML_FILE
133+ with (
134+ patch ("twyn.config.config_handler.DEFAULT_TWYN_TOML_FILE" , new = str (twyn_path )),
135+ patch ("twyn.config.config_handler.DEFAULT_PROJECT_TOML_FILE" , new = str (pyproject_toml_file )),
136+ ):
137+ assert not twyn_path .exists ()
138+ assert ConfigHandler .get_default_config_file_path () == str (pyproject_toml_file )
139+
108140
109141class TestAllowlistConfigHandler :
110142 @patch ("twyn.file_handler.file_handler.FileHandler.write" )
111143 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
112- def test_allowlist_add (self , mock_toml , mock_write_toml ) :
144+ def test_allowlist_add (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
113145 mock_toml .return_value = TOMLDocument ()
114146
115147 config = ConfigHandler (FileHandler ("some-file" ))
@@ -123,7 +155,7 @@ def test_allowlist_add(self, mock_toml, mock_write_toml):
123155
124156 @patch ("twyn.config.config_handler.ConfigHandler._write_toml" )
125157 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
126- def test_allowlist_add_duplicate_error (self , mock_toml , mock_write_toml ) :
158+ def test_allowlist_add_duplicate_error (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
127159 mock_toml .return_value = parse (dumps ({"tool" : {"twyn" : {"allowlist" : ["mypackage" ]}}}))
128160
129161 config = ConfigHandler (FileHandler ("some-file" ))
@@ -137,7 +169,7 @@ def test_allowlist_add_duplicate_error(self, mock_toml, mock_write_toml):
137169
138170 @patch ("twyn.config.config_handler.ConfigHandler._write_toml" )
139171 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
140- def test_allowlist_remove_completely (self , mock_toml , mock_write_toml ) :
172+ def test_allowlist_remove_completely (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
141173 mock_toml .return_value = parse (dumps ({"tool" : {"twyn" : {"allowlist" : ["mypackage" ]}}}))
142174
143175 config = ConfigHandler (FileHandler ("some-file" ))
@@ -147,7 +179,7 @@ def test_allowlist_remove_completely(self, mock_toml, mock_write_toml):
147179
148180 @patch ("twyn.config.config_handler.ConfigHandler._write_toml" )
149181 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
150- def test_allowlist_remove (self , mock_toml , mock_write_toml ) :
182+ def test_allowlist_remove (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
151183 mock_toml .return_value = parse (dumps ({"tool" : {"twyn" : {"allowlist" : ["mypackage" , "another-package" ]}}}))
152184
153185 config = ConfigHandler (FileHandler ("some-file" ))
@@ -157,7 +189,7 @@ def test_allowlist_remove(self, mock_toml, mock_write_toml):
157189
158190 @patch ("twyn.config.config_handler.ConfigHandler._write_toml" )
159191 @patch ("twyn.config.config_handler.ConfigHandler._read_toml" )
160- def test_allowlist_remove_non_existent_package_error (self , mock_toml , mock_write_toml ) :
192+ def test_allowlist_remove_non_existent_package_error (self , mock_toml : Mock , mock_write_toml : Mock ) -> None :
161193 mock_toml .return_value = parse (dumps ({"tool" : {"twyn" : {"allowlist" : ["mypackage" ]}}}))
162194
163195 config = ConfigHandler (FileHandler ("some-file" ))
@@ -170,7 +202,7 @@ def test_allowlist_remove_non_existent_package_error(self, mock_toml, mock_write
170202 assert not mock_write_toml .called
171203
172204 @pytest .mark .parametrize ("valid_selector" , ["first-letter" , "nearby-letter" , "all" ])
173- def test_valid_selector_methods_accepted (self , valid_selector : str , tmp_path : Path ):
205+ def test_valid_selector_methods_accepted (self , valid_selector : str , tmp_path : Path ) -> None :
174206 """Test that all valid selector methods are accepted."""
175207 pyproject_toml = tmp_path / "pyproject.toml"
176208 pyproject_toml .write_text ("" )
@@ -180,7 +212,7 @@ def test_valid_selector_methods_accepted(self, valid_selector: str, tmp_path: Pa
180212 resolved_config = config .resolve_config (selector_method = valid_selector )
181213 assert resolved_config .selector_method == valid_selector
182214
183- def test_invalid_selector_method_rejected (self , tmp_path : Path ):
215+ def test_invalid_selector_method_rejected (self , tmp_path : Path ) -> None :
184216 """Test that invalid selector methods are rejected with appropriate error."""
185217 pyproject_toml = tmp_path / "pyproject.toml"
186218 pyproject_toml .write_text ("" )
@@ -193,7 +225,7 @@ def test_invalid_selector_method_rejected(self, tmp_path: Path):
193225 assert "Invalid selector_method 'random-selector'" in error_message
194226 assert "Must be one of: all, first-letter, nearby-letter" in error_message
195227
196- def test_invalid_selector_method_from_config_file (self , tmp_path : Path ):
228+ def test_invalid_selector_method_from_config_file (self , tmp_path : Path ) -> None :
197229 """Test that invalid selector method from config file is rejected."""
198230 # Create a config file with invalid selector method
199231 pyproject_toml = tmp_path / "pyproject.toml"
0 commit comments