Skip to content

Commit ed2aa16

Browse files
authored
Merge pull request #469 from kimocoder/copilot/refactor-configuration-module
Refactor: Split monolithic `config.py` into focused `config/` package
2 parents 24c6101 + 836ef0d commit ed2aa16

16 files changed

Lines changed: 1923 additions & 1444 deletions

tests/test_config_refactor.py

Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
"""Tests for the refactored config package structure.
4+
5+
Verifies that:
6+
- All import styles continue to work (backward compatibility).
7+
- The Configuration class behaves identically after the refactor.
8+
- Sub-modules are importable and contain the expected callables.
9+
- Key configuration flows (initialization, validation, temp helpers) work.
10+
"""
11+
12+
import unittest
13+
import os
14+
import sys
15+
16+
# Mock sys.argv to prevent argparse from reading test arguments
17+
original_argv = sys.argv
18+
sys.argv = ['wifite']
19+
20+
21+
class TestConfigImports(unittest.TestCase):
22+
"""Verify that all existing import patterns still work."""
23+
24+
def test_import_configuration_from_wifite_config(self):
25+
"""Primary import style used across the codebase."""
26+
from wifite.config import Configuration
27+
self.assertIsNotNone(Configuration)
28+
29+
def test_configuration_version_accessible_at_import_time(self):
30+
"""setup.py imports Configuration.version at import time."""
31+
from wifite.config import Configuration
32+
self.assertIsNotNone(Configuration.version)
33+
self.assertIsInstance(Configuration.version, str)
34+
35+
def test_import_defaults_submodule(self):
36+
from wifite.config.defaults import initialize_defaults
37+
self.assertTrue(callable(initialize_defaults))
38+
39+
def test_import_validators_submodule(self):
40+
from wifite.config.validators import (
41+
validate,
42+
validate_eviltwin_config,
43+
validate_attack_monitor_config,
44+
validate_wpasec_config,
45+
validate_interface_name,
46+
)
47+
for fn in (validate, validate_eviltwin_config, validate_attack_monitor_config,
48+
validate_wpasec_config, validate_interface_name):
49+
self.assertTrue(callable(fn))
50+
51+
def test_import_manufacturers_submodule(self):
52+
from wifite.config.manufacturers import load_manufacturers
53+
self.assertTrue(callable(load_manufacturers))
54+
55+
def test_import_parsers_settings(self):
56+
from wifite.config.parsers.settings import (
57+
parse_settings_args,
58+
parse_encryption,
59+
parse_wep_attacks,
60+
)
61+
for fn in (parse_settings_args, parse_encryption, parse_wep_attacks):
62+
self.assertTrue(callable(fn))
63+
64+
def test_import_parsers_wep(self):
65+
from wifite.config.parsers.wep import parse_wep_args
66+
self.assertTrue(callable(parse_wep_args))
67+
68+
def test_import_parsers_wpa(self):
69+
from wifite.config.parsers.wpa import parse_wpa_args
70+
self.assertTrue(callable(parse_wpa_args))
71+
72+
def test_import_parsers_wps(self):
73+
from wifite.config.parsers.wps import parse_wps_args
74+
self.assertTrue(callable(parse_wps_args))
75+
76+
def test_import_parsers_pmkid(self):
77+
from wifite.config.parsers.pmkid import parse_pmkid_args
78+
self.assertTrue(callable(parse_pmkid_args))
79+
80+
def test_import_parsers_eviltwin(self):
81+
from wifite.config.parsers.eviltwin import (
82+
parse_eviltwin_args,
83+
display_eviltwin_interface_info,
84+
)
85+
self.assertTrue(callable(parse_eviltwin_args))
86+
self.assertTrue(callable(display_eviltwin_interface_info))
87+
88+
def test_import_parsers_attack_monitor(self):
89+
from wifite.config.parsers.attack_monitor import parse_attack_monitor_args
90+
self.assertTrue(callable(parse_attack_monitor_args))
91+
92+
def test_import_parsers_dual_interface(self):
93+
from wifite.config.parsers.dual_interface import parse_dual_interface_args
94+
self.assertTrue(callable(parse_dual_interface_args))
95+
96+
def test_import_parsers_wpasec(self):
97+
from wifite.config.parsers.wpasec import parse_wpasec_args, parse_tui_args
98+
self.assertTrue(callable(parse_wpasec_args))
99+
self.assertTrue(callable(parse_tui_args))
100+
101+
102+
class TestConfigurationInitialization(unittest.TestCase):
103+
"""Verify the Configuration.initialize() flow."""
104+
105+
def setUp(self):
106+
self._orig_argv = sys.argv[:]
107+
sys.argv = ['wifite']
108+
109+
def tearDown(self):
110+
sys.argv = self._orig_argv
111+
112+
def test_initialize_sets_defaults(self):
113+
"""initialize_defaults() sets the expected values on Configuration."""
114+
from wifite.config import Configuration
115+
from wifite.config.defaults import initialize_defaults
116+
# Apply defaults to a fresh class state (without going through full initialize)
117+
initialize_defaults(Configuration)
118+
self.assertEqual(Configuration.verbose, 0)
119+
self.assertEqual(Configuration.wpa_attack_timeout, 300)
120+
self.assertEqual(Configuration.wps_pixie_timeout, 300)
121+
self.assertEqual(Configuration.wep_pps, 600)
122+
self.assertFalse(Configuration.use_eviltwin)
123+
self.assertFalse(Configuration.use_tui)
124+
125+
def test_initialize_is_idempotent(self):
126+
"""Configuration.initialize() is a no-op after the first call."""
127+
from wifite.config import Configuration
128+
from unittest.mock import patch
129+
with patch.object(Configuration, 'load_from_arguments'):
130+
Configuration.initialized = False
131+
Configuration.initialize(load_interface=False)
132+
Configuration.verbose = 99 # change after first init
133+
Configuration.initialize(load_interface=False) # second call should be a no-op
134+
self.assertEqual(Configuration.verbose, 99)
135+
136+
def test_initialize_sets_encryption_filter(self):
137+
"""After initialize(), encryption_filter is a non-empty list."""
138+
from wifite.config import Configuration
139+
from wifite.config.defaults import initialize_defaults
140+
from wifite.config.parsers.settings import parse_encryption
141+
initialize_defaults(Configuration)
142+
parse_encryption(Configuration)
143+
self.assertIsInstance(Configuration.encryption_filter, list)
144+
self.assertGreater(len(Configuration.encryption_filter), 0)
145+
146+
def test_initialize_sets_wep_attacks(self):
147+
"""After parse_wep_attacks(), wep_attacks is a non-empty list."""
148+
from wifite.config import Configuration
149+
from wifite.config.defaults import initialize_defaults
150+
from wifite.config.parsers.settings import parse_wep_attacks
151+
initialize_defaults(Configuration)
152+
parse_wep_attacks(Configuration)
153+
self.assertIsInstance(Configuration.wep_attacks, list)
154+
self.assertGreater(len(Configuration.wep_attacks), 0)
155+
156+
157+
class TestConfigurationValidation(unittest.TestCase):
158+
"""Verify that Configuration validation methods work correctly."""
159+
160+
def setUp(self):
161+
from wifite.config import Configuration
162+
from wifite.config.defaults import initialize_defaults
163+
self._orig_argv = sys.argv[:]
164+
sys.argv = ['wifite']
165+
# Apply defaults directly to avoid full initialize() complexity
166+
initialize_defaults(Configuration)
167+
168+
def tearDown(self):
169+
sys.argv = self._orig_argv
170+
171+
def test_validate_interface_name_valid(self):
172+
from wifite.config import Configuration
173+
# Should not raise
174+
Configuration._validate_interface_name('wlan0')
175+
Configuration._validate_interface_name('wlan0mon')
176+
Configuration._validate_interface_name('eth0')
177+
Configuration._validate_interface_name('wlp2s0')
178+
179+
def test_validate_interface_name_invalid_special_chars(self):
180+
from wifite.config import Configuration
181+
with self.assertRaises(ValueError):
182+
Configuration._validate_interface_name('wlan0; rm -rf /')
183+
184+
def test_validate_interface_name_too_long(self):
185+
from wifite.config import Configuration
186+
with self.assertRaises(ValueError):
187+
Configuration._validate_interface_name('a' * 16) # >15 chars
188+
189+
def test_validate_interface_name_empty(self):
190+
from wifite.config import Configuration
191+
with self.assertRaises(ValueError):
192+
Configuration._validate_interface_name('')
193+
194+
def test_validate_pmkid_conflict(self):
195+
from wifite.config import Configuration
196+
Configuration.use_pmkid_only = True
197+
Configuration.wps_only = True
198+
with self.assertRaises(RuntimeError):
199+
Configuration.validate()
200+
201+
def test_validate_pmkid_no_pmkid_conflict(self):
202+
from wifite.config import Configuration
203+
Configuration.use_pmkid_only = True
204+
Configuration.dont_use_pmkid = True
205+
Configuration.wps_only = False
206+
with self.assertRaises(RuntimeError):
207+
Configuration.validate()
208+
209+
210+
class TestConfigurationTempDir(unittest.TestCase):
211+
"""Verify temp directory creation and cleanup."""
212+
213+
def setUp(self):
214+
from wifite.config import Configuration
215+
# Save original temp_dir and reset it for testing
216+
self._orig_temp_dir = Configuration.temp_dir
217+
Configuration.temp_dir = None
218+
219+
def tearDown(self):
220+
from wifite.config import Configuration
221+
# Clean up our test temp dir, then restore the original
222+
Configuration.delete_temp()
223+
Configuration.temp_dir = self._orig_temp_dir
224+
225+
def test_temp_creates_directory(self):
226+
from wifite.config import Configuration
227+
tmp = Configuration.temp()
228+
self.assertTrue(os.path.isdir(tmp))
229+
230+
def test_temp_returns_same_dir_on_repeated_calls(self):
231+
from wifite.config import Configuration
232+
tmp1 = Configuration.temp()
233+
tmp2 = Configuration.temp()
234+
self.assertEqual(tmp1, tmp2)
235+
236+
def test_temp_subfile(self):
237+
from wifite.config import Configuration
238+
tmp = Configuration.temp('myfile.cap')
239+
self.assertTrue(tmp.endswith('myfile.cap'))
240+
241+
def test_create_temp_is_unique(self):
242+
from wifite.config import Configuration
243+
tmp1 = Configuration.create_temp()
244+
tmp2 = Configuration.create_temp()
245+
self.assertNotEqual(tmp1, tmp2)
246+
# Clean up
247+
if os.path.exists(tmp1):
248+
os.rmdir(tmp1)
249+
if os.path.exists(tmp2):
250+
os.rmdir(tmp2)
251+
252+
def test_delete_temp_removes_directory(self):
253+
from wifite.config import Configuration
254+
tmp = Configuration.temp()
255+
self.assertTrue(os.path.isdir(tmp))
256+
Configuration.delete_temp()
257+
self.assertFalse(os.path.exists(tmp))
258+
259+
260+
class TestConfigurationClassAttributes(unittest.TestCase):
261+
"""Verify that all expected class-level attributes exist."""
262+
263+
def test_all_expected_attributes_present(self):
264+
from wifite.config import Configuration
265+
expected_attrs = [
266+
'initialized', 'verbose', 'version',
267+
'interface', 'target_bssid', 'target_essid', 'target_channel',
268+
'wpa_attack_timeout', 'wpa_deauth_timeout', 'wpa_handshake_dir',
269+
'wps_pixie', 'wps_pin', 'wps_ignore_lock', 'wps_fail_threshold',
270+
'wep_pps', 'wep_timeout', 'wep_attacks',
271+
'use_eviltwin', 'eviltwin_port', 'eviltwin_template',
272+
'dual_interface_enabled', 'interface_primary', 'interface_secondary',
273+
'wpasec_enabled', 'wpasec_api_key', 'wpasec_url',
274+
'monitor_attacks', 'monitor_duration', 'monitor_channel',
275+
'use_tui', 'tui_refresh_rate',
276+
'pmkid_timeout', 'dont_use_pmkid', 'use_pmkid_only',
277+
'wordlist', 'wordlists', 'cracked_file',
278+
'temp_dir', 'existing_commands',
279+
]
280+
for attr in expected_attrs:
281+
self.assertTrue(hasattr(Configuration, attr),
282+
f'Configuration is missing expected attribute: {attr}')
283+
284+
def test_configuration_methods_present(self):
285+
from wifite.config import Configuration
286+
expected_methods = [
287+
'initialize', 'load_manufacturers', 'get_monitor_mode_interface',
288+
'load_from_arguments', 'validate',
289+
'_validate_eviltwin_config', '_validate_attack_monitor_config',
290+
'_validate_wpasec_config', '_validate_interface_name',
291+
'parse_settings_args', 'parse_wep_args', 'parse_wpa_args',
292+
'parse_wps_args', 'parse_pmkid_args', 'parse_eviltwin_args',
293+
'_display_eviltwin_interface_info', 'parse_attack_monitor_args',
294+
'parse_dual_interface_args', 'parse_wpasec_args', 'parse_tui_args',
295+
'parse_encryption', 'parse_wep_attacks',
296+
'temp', 'create_temp', 'delete_temp',
297+
'cleanup_memory', 'exit_gracefully', 'dump',
298+
]
299+
for method in expected_methods:
300+
self.assertTrue(hasattr(Configuration, method),
301+
f'Configuration is missing expected method: {method}')
302+
303+
304+
if __name__ == '__main__':
305+
unittest.main()

0 commit comments

Comments
 (0)