44
55import os
66import sys
7- import tempfile
8- import shutil
7+ from pathlib import Path
98import logging
109import argparse
1110from unittest .mock import patch
2019import relink # noqa: E402
2120
2221
23- @pytest .fixture (scope = "function" , name = "mock_default_dirs" )
24- def fixture_mock_default_dirs (temp_dirs ):
25- """Mock the default directories to use temporary directories."""
26- source_dir = tempfile .mkdtemp (prefix = "test_default_source_" )
27- target_dir = tempfile .mkdtemp (prefix = "test_default_target_" )
28- source_dir , target_dir = temp_dirs
29-
30- with patch .object (relink , "DEFAULT_SOURCE_ROOT" , source_dir ):
31- with patch .object (relink , "DEFAULT_TARGET_ROOT" , target_dir ):
32- yield source_dir , target_dir
33-
34- # Cleanup
35- shutil .rmtree (source_dir , ignore_errors = True )
36- shutil .rmtree (target_dir , ignore_errors = True )
37-
38-
3922class TestParseArguments :
4023 """Test suite for parse_arguments function."""
4124
42- def test_default_arguments (self , mock_default_dirs ):
25+ def test_default_arguments (self , temp_dirs ):
4326 """Test that default arguments are used when none provided."""
44- source_dir , target_dir = mock_default_dirs
45- with patch ("sys.argv" , ["relink.py" ]):
27+ source_dir , target_dir = temp_dirs
28+ with patch ("sys.argv" , ["relink.py" , source_dir ]):
4629 args = relink .parse_arguments ()
47- assert args .source_root == source_dir
30+ assert args .source_root == [ source_dir ]
4831 assert args .target_root == target_dir
4932
50- def test_custom_source_root (self , mock_default_dirs , tmp_path ):
33+ def test_custom_source_root (self , temp_dirs ):
5134 """Test custom source root argument."""
52- _ , target_dir = mock_default_dirs
53- custom_source = tmp_path / "custom_source"
35+ source_dir , target_dir = temp_dirs
36+ custom_source = Path ( os . path . join ( source_dir , "custom_source" ))
5437 custom_source .mkdir ()
5538 with patch ("sys.argv" , ["relink.py" , str (custom_source )]):
5639 args = relink .parse_arguments ()
5740 assert args .source_root == [str (custom_source .resolve ())]
5841 assert args .target_root == target_dir
5942
60- def test_custom_target_root (self , mock_default_dirs , tmp_path ):
43+ def test_custom_target_root (self , temp_dirs ):
6144 """Test custom target root argument."""
62- source_dir , _ = mock_default_dirs
63- custom_target = tmp_path / "custom_target"
45+ source_dir , target_dir = temp_dirs
46+ custom_target = Path ( os . path . join ( target_dir , "custom_target" ))
6447 custom_target .mkdir ()
6548 with patch ("sys.argv" , ["relink.py" , "--target-root" , str (custom_target )]):
6649 args = relink .parse_arguments ()
67- assert args .source_root == source_dir
50+ assert args .source_root == [ source_dir ]
6851 assert args .target_root == str (custom_target .resolve ())
6952
70- def test_both_custom_paths (self , tmp_path ):
53+ def test_both_custom_paths (self , temp_dirs ):
7154 """Test both custom source and target roots."""
72- source_path = tmp_path / "custom_source"
73- target_path = tmp_path / "custom_target"
74- source_path .mkdir ()
75- target_path .mkdir ()
55+ source_root , target_root = temp_dirs
56+ source_dir = Path (os .path .join (source_root , "custom_source" ))
57+ target_dir = Path (os .path .join (target_root , "custom_target" ))
58+ source_dir .mkdir ()
59+ target_dir .mkdir ()
7660 with patch (
7761 "sys.argv" ,
7862 [
7963 "relink.py" ,
80- str (source_path ),
64+ str (source_dir ),
8165 "--target-root" ,
82- str (target_path ),
66+ str (target_dir ),
8367 ],
8468 ):
8569 args = relink .parse_arguments ()
86- assert args .source_root == [str (source_path .resolve ())]
87- assert args .target_root == str (target_path .resolve ())
70+ assert args .source_root == [str (source_dir .resolve ())]
71+ assert args .target_root == str (target_dir .resolve ())
8872
89- def test_verbose_flag (self , mock_default_dirs ): # pylint: disable=unused-argument
73+ def test_verbose_flag (self , temp_dirs ): # pylint: disable=unused-argument
9074 """Test that --verbose flag is parsed correctly."""
9175 with patch ("sys.argv" , ["relink.py" , "--verbose" ]):
9276 args = relink .parse_arguments ()
9377 assert args .verbose is True
9478 assert args .quiet is False
9579
96- def test_quiet_flag (self , mock_default_dirs ): # pylint: disable=unused-argument
80+ def test_quiet_flag (self , temp_dirs ): # pylint: disable=unused-argument
9781 """Test that --quiet flag is parsed correctly."""
9882 with patch ("sys.argv" , ["relink.py" , "--quiet" ]):
9983 args = relink .parse_arguments ()
10084 assert args .quiet is True
10185 assert args .verbose is False
10286
103- def test_verbose_short_flag (
104- self , mock_default_dirs
105- ): # pylint: disable=unused-argument
87+ def test_verbose_short_flag (self , temp_dirs ): # pylint: disable=unused-argument
10688 """Test that -v flag is parsed correctly."""
10789 with patch ("sys.argv" , ["relink.py" , "-v" ]):
10890 args = relink .parse_arguments ()
10991 assert args .verbose is True
11092
111- def test_quiet_short_flag (
112- self , mock_default_dirs
113- ): # pylint: disable=unused-argument
93+ def test_quiet_short_flag (self , temp_dirs ): # pylint: disable=unused-argument
11494 """Test that -q flag is parsed correctly."""
11595 with patch ("sys.argv" , ["relink.py" , "-q" ]):
11696 args = relink .parse_arguments ()
11797 assert args .quiet is True
11898
119- def test_default_verbosity (
120- self , mock_default_dirs
121- ): # pylint: disable=unused-argument
99+ def test_default_verbosity (self , temp_dirs ): # pylint: disable=unused-argument
122100 """Test that default verbosity has both flags as False."""
123101 with patch ("sys.argv" , ["relink.py" ]):
124102 args = relink .parse_arguments ()
125103 assert args .verbose is False
126104 assert args .quiet is False
127105
128- def test_verbose_and_quiet_mutually_exclusive (self , mock_default_dirs ):
106+ def test_verbose_and_quiet_mutually_exclusive (self , temp_dirs ):
129107 """Test that --verbose and --quiet cannot be used together."""
130108 # pylint: disable=unused-argument
131109 with patch ("sys.argv" , ["relink.py" , "--verbose" , "--quiet" ]):
@@ -134,7 +112,7 @@ def test_verbose_and_quiet_mutually_exclusive(self, mock_default_dirs):
134112 # Mutually exclusive arguments cause SystemExit with code 2
135113 assert exc_info .value .code == 2
136114
137- def test_verbose_and_quiet_short_flags_mutually_exclusive (self , mock_default_dirs ):
115+ def test_verbose_and_quiet_short_flags_mutually_exclusive (self , temp_dirs ):
138116 """Test that -v and -q cannot be used together."""
139117 # pylint: disable=unused-argument
140118 with patch ("sys.argv" , ["relink.py" , "-v" , "-q" ]):
@@ -143,40 +121,40 @@ def test_verbose_and_quiet_short_flags_mutually_exclusive(self, mock_default_dir
143121 # Mutually exclusive arguments cause SystemExit with code 2
144122 assert exc_info .value .code == 2
145123
146- def test_dry_run_flag (self , mock_default_dirs ):
124+ def test_dry_run_flag (self , temp_dirs ):
147125 """Test that --dry-run flag is parsed correctly."""
148126 # pylint: disable=unused-argument
149127 with patch ("sys.argv" , ["relink.py" , "--dry-run" ]):
150128 args = relink .parse_arguments ()
151129 assert args .dry_run is True
152130
153- def test_dry_run_default (self , mock_default_dirs ):
131+ def test_dry_run_default (self , temp_dirs ):
154132 """Test that dry_run defaults to False."""
155133 # pylint: disable=unused-argument
156134 with patch ("sys.argv" , ["relink.py" ]):
157135 args = relink .parse_arguments ()
158136 assert args .dry_run is False
159137
160- def test_timing_flag (self , mock_default_dirs ):
138+ def test_timing_flag (self , temp_dirs ):
161139 """Test that --timing flag is parsed correctly."""
162140 # pylint: disable=unused-argument
163141 with patch ("sys.argv" , ["relink.py" , "--timing" ]):
164142 args = relink .parse_arguments ()
165143 assert args .timing is True
166144
167- def test_timing_default (self , mock_default_dirs ):
145+ def test_timing_default (self , temp_dirs ):
168146 """Test that timing defaults to False."""
169147 # pylint: disable=unused-argument
170148 with patch ("sys.argv" , ["relink.py" ]):
171149 args = relink .parse_arguments ()
172150 assert args .timing is False
173151
174- def test_multiple_source_roots (self , mock_default_dirs , tmp_path ):
152+ def test_multiple_source_roots (self , temp_dirs ):
175153 """Test that multiple source root arguments are parsed correctly."""
176- _ , target_dir = mock_default_dirs
177- source1 = tmp_path / "source1"
178- source2 = tmp_path / "source2"
179- source3 = tmp_path / "source3"
154+ inputdata_root , target_dir = temp_dirs
155+ source1 = Path ( os . path . join ( inputdata_root , "source1" ))
156+ source2 = Path ( os . path . join ( inputdata_root , "source2" ))
157+ source3 = Path ( os . path . join ( inputdata_root , "source3" ))
180158 source1 .mkdir ()
181159 source2 .mkdir ()
182160 source3 .mkdir ()
@@ -189,11 +167,12 @@ def test_multiple_source_roots(self, mock_default_dirs, tmp_path):
189167 assert str (source3 .resolve ()) in args .source_root
190168 assert args .target_root == target_dir
191169
192- def test_multiple_source_roots_with_target (self , tmp_path ):
170+ def test_multiple_source_roots_with_target (self , temp_dirs ):
193171 """Test multiple source roots with custom target root."""
194- source1 = tmp_path / "source1"
195- source2 = tmp_path / "source2"
196- target = tmp_path / "target"
172+ inputdata_root , target_dir = temp_dirs
173+ source1 = Path (os .path .join (inputdata_root , "source1" ))
174+ source2 = Path (os .path .join (inputdata_root , "source2" ))
175+ target = Path (os .path .join (target_dir , "target" ))
197176 source1 .mkdir ()
198177 source2 .mkdir ()
199178 target .mkdir ()
@@ -330,3 +309,26 @@ def test_process_args_modifies_args_in_place(self):
330309 # Should be the same object, modified in place
331310 assert args is original_args
332311 assert hasattr (args , "log_level" )
312+
313+ def test_error_if_source_not_in_inputdata (self ):
314+ """Test that process_args errors if source isn't in inputdata_root."""
315+ args = argparse .Namespace (
316+ quiet = False , verbose = False , source_root = "abc123" , inputdata_root = "def456"
317+ )
318+ with pytest .raises (argparse .ArgumentTypeError ) as exc_info :
319+ relink .process_args (args )
320+ assert "not under inputdata root" in str (exc_info .value )
321+
322+ def test_error_if_target_in_inputdata (self ):
323+ """Test that process_args errors if target is in inputdata_root."""
324+ inputdata_root = "inputdata"
325+ target_root = os .path .join (inputdata_root , "abc123" )
326+ args = argparse .Namespace (
327+ quiet = False ,
328+ verbose = False ,
329+ target_root = target_root ,
330+ inputdata_root = inputdata_root ,
331+ )
332+ with pytest .raises (argparse .ArgumentTypeError ) as exc_info :
333+ relink .process_args (args )
334+ assert "must not be under inputdata root" in str (exc_info .value )
0 commit comments