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