Open-AutoTools 0.0.3rc4__py3-none-any.whl → 0.0.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. autotools/autocaps/commands.py +3 -7
  2. autotools/autocaps/core.py +5 -4
  3. autotools/autoip/commands.py +8 -12
  4. autotools/autoip/core.py +151 -200
  5. autotools/autolower/commands.py +3 -7
  6. autotools/autolower/core.py +4 -3
  7. autotools/autopassword/commands.py +27 -33
  8. autotools/autopassword/core.py +32 -73
  9. autotools/autotest/__init__.py +2 -0
  10. autotools/autotest/commands.py +206 -0
  11. autotools/cli.py +123 -62
  12. autotools/utils/commands.py +13 -0
  13. autotools/utils/loading.py +14 -6
  14. autotools/utils/performance.py +424 -0
  15. autotools/utils/requirements.py +21 -0
  16. autotools/utils/text.py +16 -0
  17. autotools/utils/updates.py +30 -22
  18. autotools/utils/version.py +69 -63
  19. open_autotools-0.0.4.dist-info/METADATA +84 -0
  20. open_autotools-0.0.4.dist-info/RECORD +30 -0
  21. {Open_AutoTools-0.0.3rc4.dist-info → open_autotools-0.0.4.dist-info}/WHEEL +1 -1
  22. {Open_AutoTools-0.0.3rc4.dist-info → open_autotools-0.0.4.dist-info}/entry_points.txt +0 -3
  23. Open_AutoTools-0.0.3rc4.dist-info/METADATA +0 -308
  24. Open_AutoTools-0.0.3rc4.dist-info/RECORD +0 -44
  25. autotools/autocaps/tests/__init__.py +0 -1
  26. autotools/autocaps/tests/test_autocaps_core.py +0 -45
  27. autotools/autocaps/tests/test_autocaps_integration.py +0 -46
  28. autotools/autodownload/__init__.py +0 -0
  29. autotools/autodownload/commands.py +0 -38
  30. autotools/autodownload/core.py +0 -373
  31. autotools/autoip/tests/__init__.py +0 -1
  32. autotools/autoip/tests/test_autoip_core.py +0 -72
  33. autotools/autoip/tests/test_autoip_integration.py +0 -92
  34. autotools/autolower/tests/__init__.py +0 -1
  35. autotools/autolower/tests/test_autolower_core.py +0 -45
  36. autotools/autolower/tests/test_autolower_integration.py +0 -46
  37. autotools/autospell/__init__.py +0 -3
  38. autotools/autospell/commands.py +0 -123
  39. autotools/autospell/core.py +0 -222
  40. autotools/autotranslate/__init__.py +0 -3
  41. autotools/autotranslate/commands.py +0 -42
  42. autotools/autotranslate/core.py +0 -52
  43. autotools/test/__init__.py +0 -3
  44. autotools/test/commands.py +0 -120
  45. {Open_AutoTools-0.0.3rc4.dist-info → open_autotools-0.0.4.dist-info/licenses}/LICENSE +0 -0
  46. {Open_AutoTools-0.0.3rc4.dist-info → open_autotools-0.0.4.dist-info}/top_level.txt +0 -0
@@ -1,373 +0,0 @@
1
- import requests
2
- import os
3
- from pathlib import Path
4
- from urllib.parse import urlsplit
5
- from tqdm import tqdm
6
- import yt_dlp
7
- import platform
8
- import subprocess
9
- import json
10
- from rich.progress import Progress
11
- from ..utils.loading import LoadingAnimation
12
-
13
-
14
- # FUNCTION TO GET DEFAULT DOWNLOAD DIRECTORY
15
- def get_default_download_dir():
16
- return Path(os.getenv('USERPROFILE') if os.name == 'nt' else Path.home()) / 'Downloads'
17
-
18
-
19
- # FUNCTION TO GET FILENAME FROM URL WITH DEFAULT AND EXTENSION HANDLING
20
- def get_filename_from_url(url):
21
- filename = os.path.basename(urlsplit(url).path)
22
- if not filename: # IF NO FILENAME IN URL
23
- return "downloaded_file"
24
- if not Path(filename).suffix: # IF NO EXTENSION IN FILENAME
25
- return f"{filename}.bin"
26
- return filename
27
-
28
-
29
- # FUNCTION TO OPEN DOWNLOAD DIRECTORY AFTER DOWNLOAD IS COMPLETE
30
- def open_download_folder(path):
31
- """OPEN THE DOWNLOAD FOLDER IN THE DEFAULT FILE MANAGER"""
32
- # SKIP IN CI ENVIRONMENT
33
- if os.environ.get('CI'):
34
- return
35
-
36
- try:
37
- if platform.system() == 'Darwin': # MACOS
38
- subprocess.run(['open', str(path)], check=True)
39
- elif platform.system() == 'Windows': # WINDOWS
40
- os.startfile(str(path))
41
- else: # LINUX
42
- subprocess.run(['xdg-open', str(path)], check=True)
43
- except Exception as e:
44
- print(f"Failed to open download folder: {e}")
45
-
46
-
47
- # FUNCTION TO VALIDATE YOUTUBE URL FORMAT
48
- def validate_youtube_url(url):
49
- """BASIC URL VALIDATION WITH PROPER FORMAT CHECK"""
50
- # CHECK IF URL CONTAINS YOUTUBE DOMAIN
51
- is_youtube = any(domain in url for domain in ["youtube.com", "youtu.be", "music.youtube.com"])
52
-
53
- # CHECK IF URL HAS PROPER VIDEO ID FORMAT
54
- has_video_id = False
55
- if "youtube.com/watch" in url and "v=" in url:
56
- has_video_id = True
57
- elif "youtu.be/" in url and len(url.split("youtu.be/")[1]) > 0:
58
- has_video_id = True
59
- elif any(pattern in url for pattern in ["/watch/", "/shorts/", "/live/"]):
60
- path_parts = url.split("/")
61
- has_video_id = len(path_parts[-1]) > 0
62
- elif "attribution_link" in url and "watch?v=" in url:
63
- has_video_id = True
64
-
65
- return is_youtube and has_video_id
66
-
67
-
68
- # FUNCTION TO DOWNLOAD FILES WITH REQUESTS, INCLUDING ERROR HANDLING AND PROGRESS BAR
69
- def download_file(url):
70
- download_dir = get_default_download_dir()
71
- filename = get_filename_from_url(url)
72
- dest_file = download_dir / filename
73
-
74
- try:
75
- with requests.get(url, stream=True) as response:
76
- response.raise_for_status()
77
-
78
- total_size = int(response.headers.get('content-length', 0))
79
- block_size = 1024 # 1KB
80
-
81
- with tqdm(total=total_size if total_size else None, unit='iB', unit_scale=True, desc=f"Downloading {filename}", leave=True) as tqdm_bar:
82
- with open(dest_file, 'wb') as file:
83
- for chunk in response.iter_content(chunk_size=block_size):
84
- if chunk:
85
- file.write(chunk)
86
- tqdm_bar.update(len(chunk))
87
-
88
- # AUTOMATICALLY OPEN DOWNLOAD FOLDER AFTER FILE DOWNLOAD IS COMPLETE
89
- open_download_folder(download_dir)
90
- except requests.exceptions.RequestException as e:
91
- print(f"Error during file download: {e}")
92
-
93
- # FUNCTION TO GET CONSENT FILE PATH
94
- def get_consent_file_path():
95
- """GET PATH TO STORE CONSENT STATUS"""
96
- # INFO: delete consent file with "rm -f ~/.autotools/consent.json" if you want to force new consent in local development
97
- return Path.home() / '.autotools' / 'consent.json'
98
-
99
- # FUNCTION TO LOAD CONSENT STATUS
100
- def load_consent_status():
101
- """LOAD SAVED CONSENT STATUS"""
102
- try:
103
- consent_file = get_consent_file_path()
104
-
105
- # FORCE NEW CONSENT IF FILE DOESN'T EXIST OR IS EMPTY
106
- if not consent_file.exists():
107
- return False
108
-
109
- # READ CONSENT STATUS
110
- with open(consent_file) as f:
111
- data = json.load(f)
112
- return data.get('youtube_consent', False)
113
- except Exception:
114
- # IF ANY ERROR OCCURS, FORCE NEW CONSENT
115
- return False
116
-
117
- # FUNCTION TO SAVE CONSENT STATUS
118
- def save_consent_status(status):
119
- """SAVE CONSENT STATUS"""
120
- try:
121
- consent_file = get_consent_file_path()
122
- consent_file.parent.mkdir(exist_ok=True)
123
-
124
- # SAVE CONSENT STATUS TO FILE
125
- with open(consent_file, 'w') as f:
126
- json.dump({'youtube_consent': status}, f)
127
- return True
128
- except Exception:
129
- # IF SAVING FAILS, RETURN FALSE TO FORCE NEW CONSENT NEXT TIME
130
- return False
131
-
132
- # FUNCTION TO GET USER CONSENT WITH INTERACTIVE PROMPT
133
- def get_user_consent():
134
- """GET USER CONSENT WITH INTERACTIVE PROMPT"""
135
- print("\n⚠️ Important Notice:")
136
- print("This tool will:")
137
- print("1. Download video content from YouTube")
138
- print("2. Save files to your local machine")
139
- print("3. Use mobile API for better compatibility")
140
-
141
- # GET USER CONSENT WITH INTERACTIVE PROMPT
142
- while True:
143
- response = input("\nDo you consent to these actions? (yes/no): ").lower()
144
- if response in ['yes', 'y']:
145
- save_consent_status(True)
146
- return True
147
- elif response in ['no', 'n']:
148
- save_consent_status(False)
149
- return False
150
- print("Please answer 'yes' or 'no'")
151
-
152
-
153
- # FUNCTION TO CHECK IF VIDEO EXISTS AND GET USER CONSENT FOR REPLACEMENT
154
- def check_existing_video(info, format='mp4'):
155
- """CHECK IF VIDEO EXISTS AND ASK FOR REPLACEMENT"""
156
- download_dir = get_default_download_dir()
157
- title = info.get('title', '').replace('/', '_') # SANITIZE TITLE
158
- filename = f"{title}.{format}"
159
- filepath = download_dir / filename
160
-
161
- # CHECK IF FILE EXISTS AND ASK FOR REPLACEMENT
162
- if filepath.exists():
163
- print(f"\n⚠️ File already exists: {filename}")
164
- while True:
165
- response = input("Do you want to replace it? (yes/no): ").lower()
166
- if response in ['yes', 'y']:
167
- return True
168
- elif response in ['no', 'n']:
169
- # OPEN DOWNLOADS FOLDER TO SHOW EXISTING FILE
170
- open_download_folder(download_dir)
171
- return False
172
- print("Please answer 'yes' or 'no'")
173
- return True
174
-
175
-
176
- # FUNCTION TO DOWNLOAD YOUTUBE VIDEOS WITH YT-DLP AND SPECIFIED FORMAT AND QUALITY
177
- def download_youtube_video(url, format='mp4', quality='best'):
178
- """DOWNLOAD VIDEO WITH CONSENT CHECK"""
179
- # VALIDATE URL FIRST
180
- if not validate_youtube_url(url):
181
- print("\n❌ Invalid YouTube URL")
182
- return False
183
-
184
- # CHECK FOR SAVED CONSENT FIRST AND GET NEW CONSENT IF NEEDED
185
- if not load_consent_status() and not get_user_consent():
186
- print("\n❌ Download cancelled by user")
187
- return False
188
-
189
- # FIRST CHECK VIDEO INFO AND EXISTENCE
190
- try:
191
- with yt_dlp.YoutubeDL({
192
- 'quiet': True,
193
- 'no_warnings': True,
194
- 'extractor_args': {'youtube': {
195
- 'player_client': ['web', 'android'],
196
- 'formats': ['missing_pot'] # ALLOW FORMATS WITHOUT PO TOKEN
197
- }}
198
- }) as ydl:
199
- info = ydl.extract_info(url, download=False)
200
- formats = info.get('formats', [])
201
- if not formats:
202
- print("\n❌ No formats available for this video")
203
- return False
204
-
205
- # FIND BEST AVAILABLE QUALITY
206
- best_height = 0
207
- for f in formats:
208
- height = f.get('height')
209
- if height is not None and height > best_height:
210
- best_height = height
211
-
212
- # IF NO VALID HEIGHT FOUND, DEFAULT TO 1080P
213
- if best_height == 0:
214
- best_height = 1080
215
-
216
- # IF QUALITY IS 'BEST', USE THE BEST AVAILABLE
217
- if quality == 'best':
218
- height = best_height
219
- # ASK FOR CONFIRMATION IF 4K OR HIGHER (ONLY FOR MP4)
220
- if format == 'mp4' and height >= 2160:
221
- print(f"\n⚠️ This video is available in {height}p quality!")
222
- while True:
223
- response = input(f"Do you want to download in {height}p quality? (yes/no): ").lower()
224
- if response in ['no', 'n']:
225
- height = 1080
226
- print("\nDowngrading to 1080p quality.")
227
- break
228
- elif response in ['yes', 'y']:
229
- break
230
- print("Please answer 'yes' or 'no'")
231
- else:
232
- # EXTRACT HEIGHT FROM QUALITY STRING
233
- try:
234
- height = int(quality.lower().replace('p', ''))
235
- except ValueError:
236
- height = 1080 # DEFAULT TO 1080P IF INVALID FORMAT
237
-
238
- # CHECK IF FILE EXISTS AND GET REPLACEMENT CONSENT
239
- force_download = check_existing_video(info, format)
240
- if not force_download:
241
- print("\n❌ Download cancelled - file already exists")
242
- return False
243
-
244
- # OPEN DOWNLOADS FOLDER IF STARTING NEW DOWNLOAD OR REPLACING
245
- download_dir = get_default_download_dir()
246
- open_download_folder(download_dir)
247
-
248
- except Exception as e:
249
- print(f"\n❌ Error checking video: {str(e)}")
250
- return False
251
-
252
- loading = LoadingAnimation()
253
-
254
- # START LOADING FOR DOWNLOAD PROCESS
255
- with loading:
256
- loading._spinner.start()
257
- print("\n🔍 Starting download...")
258
-
259
- print(f"\n🎥 Downloading video from: {url}")
260
- if format == 'mp3':
261
- print(f"📋 Format: {format}\n")
262
- else:
263
- print(f"📋 Format: {format}, Quality: {height}p\n")
264
-
265
- # YT-DLP PERMISSION OPTIONS FOR DOWNLOADING YOUTUBE VIDEOS
266
- ydl_opts = {
267
- 'format': f'bestvideo[height={height}][ext=mp4]+bestaudio[ext=m4a]/bestvideo[height<={height}][ext=mp4]+bestaudio[ext=m4a]/best[height<={height}][ext=mp4]/best[ext=mp4]/best' if format == 'mp4' else 'bestaudio/best',
268
- 'postprocessors': [{
269
- 'key': 'FFmpegExtractAudio',
270
- 'preferredcodec': 'mp3',
271
- 'preferredquality': '192',
272
- }] if format == 'mp3' else [],
273
- 'quiet': True,
274
- 'no_warnings': True,
275
- 'progress': True,
276
- 'progress_hooks': [lambda d: update_progress(d)],
277
- 'extractor_args': {
278
- 'youtube': {
279
- 'player_client': ['web', 'android'], # USE WEB CLIENT FIRST
280
- 'formats': ['missing_pot'], # ALLOW FORMATS WITHOUT PO TOKEN
281
- 'player_skip': ['configs', 'webpage'] # SKIP UNNECESSARY CONFIGS
282
- }
283
- },
284
- 'http_headers': {
285
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
286
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
287
- 'Accept-Language': 'en-us,en;q=0.5',
288
- 'Sec-Fetch-Mode': 'navigate'
289
- },
290
- 'outtmpl': str(download_dir / '%(title)s.%(ext)s'), # SET OUTPUT TEMPLATE
291
- 'overwrites': True, # FORCE OVERWRITE IF USER CONSENTED
292
- 'no_check_certificates': True, # SKIP CERTIFICATE VALIDATION
293
- 'cookiesfrombrowser': ('chrome',), # USE CHROME COOKIES IF AVAILABLE
294
- }
295
-
296
- try:
297
- # THEN DOWNLOAD
298
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
299
- ydl.download([url])
300
- print("\n✅ Download completed successfully!")
301
- return True
302
- except Exception as e:
303
- error_msg = str(e)
304
- if "Requested format is not available" in error_msg:
305
- print("\n❌ Format not available. Available formats are:")
306
- for f in formats:
307
- print(f"- {f.get('format_id', 'N/A')}: {f.get('ext', 'N/A')} ({f.get('format_note', 'N/A')})")
308
- else:
309
- print(f"\n❌ ERROR: {error_msg}")
310
- return False
311
-
312
-
313
- # FUNCTION TO LIST AVAILABLE FORMATS FOR A YOUTUBE VIDEO
314
- def list_available_formats(url):
315
- try:
316
- with yt_dlp.YoutubeDL({'quiet': True}) as ydl:
317
- info_dict = ydl.extract_info(url, download=False)
318
- formats = info_dict.get('formats', None)
319
- if formats:
320
- for f in formats:
321
- print(f"Format: {f['format_id']}, Resolution: {f.get('resolution')}, Extension: {f['ext']}")
322
- except yt_dlp.utils.DownloadError as e:
323
- print(f"Error fetching formats: {e}")
324
- except Exception as e:
325
- print(f"Unexpected error: {e}")
326
-
327
- pbar = None # GLOBAL VARIABLE TO STORE PROGRESS BAR
328
-
329
-
330
- # FUNCTION TO UPDATE PROGRESS BAR
331
- def update_progress(d):
332
- global pbar
333
- if d['status'] == 'downloading':
334
- total = d.get('total_bytes', 0)
335
- downloaded = d.get('downloaded_bytes', 0)
336
-
337
- if pbar is None:
338
- pbar = tqdm(total=total, unit='B', unit_scale=True, desc="⏳ Downloading", leave=True, ncols=80, bar_format='{desc}: {percentage:3.0f}%|{bar}| {n_fmt}/{total_fmt} [{rate_fmt}]')
339
-
340
- if total > 0:
341
- pbar.n = downloaded
342
- pbar.total = total
343
- pbar.refresh()
344
-
345
- elif d['status'] == 'finished' and pbar:
346
- pbar.close()
347
- pbar = None
348
-
349
-
350
- # FUNCTION TO DOWNLOAD FILE WITH SPECIFIC HANDLING AND FOLDER OPENING
351
- def download_file_with_tqdm(url):
352
- download_dir = get_default_download_dir()
353
- filename = get_filename_from_url(url)
354
- dest_file = download_dir / filename
355
-
356
- try:
357
- with requests.get(url, stream=True) as response:
358
- response.raise_for_status()
359
-
360
- total_size = int(response.headers.get('content-length', 0))
361
- block_size = 1024 # 1KB
362
-
363
- with tqdm(total=total_size if total_size else None, unit='iB', unit_scale=True, desc=f"Downloading {filename}", leave=True) as tqdm_bar:
364
- with open(dest_file, 'wb') as file:
365
- for chunk in response.iter_content(chunk_size=block_size):
366
- if chunk:
367
- file.write(chunk)
368
- tqdm_bar.update(len(chunk))
369
-
370
- # AUTOMATICALLY OPEN DOWNLOAD FOLDER AFTER FILE DOWNLOAD IS COMPLETE
371
- open_download_folder(download_dir)
372
- except requests.exceptions.RequestException as e:
373
- print(f"Error during file download: {e}")
@@ -1 +0,0 @@
1
- # INIT FILE FOR TESTS
@@ -1,72 +0,0 @@
1
- import pytest
2
- from unittest.mock import patch, Mock
3
- from autotools.autoip.core import get_public_ip, get_local_ip, get_ip_info
4
-
5
- # MOCK DATA
6
- MOCK_IP_INFO = {
7
- 'ip': '8.8.8.8',
8
- 'city': 'Mountain View',
9
- 'region': 'California',
10
- 'country': 'US',
11
- 'loc': '37.4056,-122.0775',
12
- 'org': 'Google LLC',
13
- 'timezone': 'America/Los_Angeles'
14
- }
15
-
16
- # UNIT TESTS
17
-
18
- # TEST FOR PUBLIC IP RETRIEVAL
19
- @patch('requests.get')
20
- def test_get_public_ip(mock_get):
21
- """TEST PUBLIC IP RETRIEVAL"""
22
- mock_get.return_value.text = "1.2.3.4"
23
- ip = get_public_ip()
24
- assert ip == "1.2.3.4"
25
- mock_get.assert_called_once()
26
-
27
- # TEST FOR LOCAL IP RETRIEVAL
28
- @patch('socket.socket')
29
- @patch('netifaces.gateways')
30
- @patch('netifaces.ifaddresses')
31
- def test_get_local_ip(mock_ifaddresses, mock_gateways, mock_socket):
32
- """TEST LOCAL IP RETRIEVAL"""
33
- # MOCK NETIFACES
34
- mock_gateways.return_value = {'default': {2: ('192.168.1.1', 'eth0')}}
35
- mock_ifaddresses.return_value = {2: [{'addr': '192.168.1.100'}]}
36
-
37
- ip = get_local_ip()
38
- assert ip == "192.168.1.100"
39
-
40
- # TEST FOR IP INFO RETRIEVAL
41
- @patch('requests.get')
42
- def test_get_ip_info(mock_get):
43
- """TEST IP INFO RETRIEVAL"""
44
- mock_get.return_value.json.return_value = MOCK_IP_INFO
45
- info = get_ip_info()
46
- assert isinstance(info, dict)
47
- assert info == MOCK_IP_INFO
48
-
49
- # TEST FOR IP INFO WITH SPECIFIC IP
50
- @patch('requests.get')
51
- def test_get_ip_info_with_ip(mock_get):
52
- """TEST IP INFO WITH SPECIFIC IP"""
53
- mock_get.return_value.json.return_value = MOCK_IP_INFO
54
- test_ip = "8.8.8.8" # GOOGLE DNS
55
- info = get_ip_info(test_ip)
56
- assert isinstance(info, dict)
57
- assert info['ip'] == test_ip
58
- assert 'Google' in info['org']
59
-
60
- # TEST FOR IP INFO WITH INVALID IP
61
- def test_get_ip_info_invalid():
62
- """TEST IP INFO WITH INVALID IP"""
63
- with pytest.raises(ValueError):
64
- get_ip_info("invalid.ip.address")
65
-
66
- # TEST FOR IP INFO WITH PRIVATE IP
67
- def test_get_ip_info_private():
68
- """TEST IP INFO WITH PRIVATE IP"""
69
- private_ips = ["192.168.1.1", "10.0.0.1", "172.16.0.1"]
70
- for ip in private_ips:
71
- with pytest.raises(ValueError):
72
- get_ip_info(ip)
@@ -1,92 +0,0 @@
1
- import pytest
2
- from unittest.mock import patch, Mock
3
- from click.testing import CliRunner
4
- from autotools.cli import autoip
5
-
6
- # MOCK DATA
7
- MOCK_IP_INFO = {
8
- 'ip': '8.8.8.8',
9
- 'city': 'Mountain View',
10
- 'region': 'California',
11
- 'country': 'US',
12
- 'loc': '37.4056,-122.0775',
13
- 'org': 'Google LLC',
14
- 'timezone': 'America/Los_Angeles'
15
- }
16
-
17
- # INTEGRATION TESTS
18
-
19
- # TEST FOR BASIC CLI FUNCTIONALITY
20
- @patch('autotools.autoip.core.get_local_ips')
21
- @patch('autotools.autoip.core.get_public_ips')
22
- def test_autoip_cli_basic(mock_public_ips, mock_local_ips):
23
- """TEST BASIC CLI FUNCTIONALITY"""
24
- mock_local_ips.return_value = {
25
- 'ipv4': ['192.168.1.100'],
26
- 'ipv6': ['fe80::1']
27
- }
28
- mock_public_ips.return_value = {
29
- 'ipv4': '1.2.3.4',
30
- 'ipv6': None
31
- }
32
-
33
- runner = CliRunner()
34
- result = runner.invoke(autoip)
35
- assert result.exit_code == 0
36
- assert "192.168.1.100" in result.output
37
- assert "1.2.3.4" in result.output
38
- assert "fe80::1" in result.output
39
-
40
- # TEST FOR CONNECTIVITY TEST
41
- @patch('autotools.autoip.core.test_connectivity')
42
- def test_autoip_cli_test(mock_test):
43
- """TEST CONNECTIVITY TEST"""
44
- mock_test.return_value = [
45
- ('Google DNS', True, 20),
46
- ('CloudFlare', False, None)
47
- ]
48
-
49
- runner = CliRunner()
50
- result = runner.invoke(autoip, ['--test'])
51
- assert result.exit_code == 0
52
- assert "Google DNS" in result.output
53
- assert "CloudFlare" in result.output
54
- assert "✓ 20ms" in result.output
55
- assert "✗ Failed" in result.output
56
-
57
- # TEST FOR SPEED TEST
58
- @patch('autotools.autoip.core.run_speedtest')
59
- def test_autoip_cli_speed(mock_speed):
60
- """TEST SPEED TEST"""
61
- mock_speed.return_value = True
62
-
63
- runner = CliRunner()
64
- result = runner.invoke(autoip, ['--speed'])
65
- assert result.exit_code == 0
66
- assert "Running speed test" in result.output
67
- assert "completed successfully" in result.output
68
-
69
- # TEST FOR LOCATION INFO DISPLAY
70
- @patch('autotools.autoip.core.get_ip_info')
71
- def test_autoip_cli_location(mock_get_info):
72
- """TEST LOCATION INFO DISPLAY"""
73
- mock_get_info.return_value = MOCK_IP_INFO
74
-
75
- runner = CliRunner()
76
- result = runner.invoke(autoip, ['--location'])
77
- assert result.exit_code == 0
78
- assert "Mountain View" in result.output
79
- assert "California" in result.output
80
- assert "Google LLC" in result.output
81
-
82
- # TEST FOR HELP DISPLAY
83
- def test_autoip_cli_help():
84
- """TEST HELP DISPLAY"""
85
- runner = CliRunner()
86
- result = runner.invoke(autoip, ['--help'])
87
- assert result.exit_code == 0
88
- assert "Usage:" in result.output
89
- assert "Options:" in result.output
90
- assert "--test" in result.output
91
- assert "--speed" in result.output
92
- assert "--location" in result.output
@@ -1 +0,0 @@
1
- # INIT FILE FOR TESTS
@@ -1,45 +0,0 @@
1
- import pytest
2
- from autotools.autolower.core import autolower_transform
3
-
4
- # UNIT TESTS
5
-
6
- # TEST FOR BASIC STRING TRANSFORMATION
7
- def test_autolower_transform_basic():
8
- """TEST BASIC STRING TRANSFORMATION"""
9
- assert autolower_transform("HELLO") == "hello"
10
- assert autolower_transform("Hello World") == "hello world"
11
- assert autolower_transform("123") == "123"
12
-
13
- # TEST FOR EMPTY STRING
14
- def test_autolower_transform_empty():
15
- """TEST EMPTY STRING"""
16
- assert autolower_transform("") == ""
17
-
18
- # TEST FOR SPECIAL CHARACTERS
19
- def test_autolower_transform_special_chars():
20
- """TEST STRING WITH SPECIAL CHARACTERS"""
21
- assert autolower_transform("HELLO@WORLD.COM") == "hello@world.com"
22
- assert autolower_transform("HELLO-WORLD!") == "hello-world!"
23
-
24
- # TEST FOR MIXED CASE STRING
25
- def test_autolower_transform_mixed_case():
26
- """TEST MIXED CASE STRING"""
27
- assert autolower_transform("HeLLo WoRLD") == "hello world"
28
-
29
- # TEST FOR WHITESPACE
30
- def test_autolower_transform_whitespace():
31
- """TEST STRING WITH WHITESPACE"""
32
- assert autolower_transform(" HELLO WORLD ") == " hello world "
33
- assert autolower_transform("\tHELLO\nWORLD") == "\thello\nworld"
34
-
35
- # TEST FOR NUMBERS
36
- def test_autolower_transform_numbers():
37
- """TEST STRING WITH NUMBERS"""
38
- assert autolower_transform("HELLO123WORLD") == "hello123world"
39
- assert autolower_transform("123HELLO456WORLD789") == "123hello456world789"
40
-
41
- # TEST FOR UNICODE CHARACTERS
42
- def test_autolower_transform_unicode():
43
- """TEST UNICODE CHARACTERS"""
44
- assert autolower_transform("HÉLLO WÖRLD") == "héllo wörld"
45
- assert autolower_transform("こんにちは") == "こんにちは" # JAPANESE SHOULD REMAIN UNCHANGED
@@ -1,46 +0,0 @@
1
- import pytest
2
- from click.testing import CliRunner
3
- from autotools.cli import autolower
4
-
5
- # INTEGRATION TESTS
6
-
7
- # TEST FOR BASIC CLI FUNCTIONALITY
8
- def test_autolower_cli_basic():
9
- """TEST BASIC CLI FUNCTIONALITY"""
10
- runner = CliRunner()
11
- result = runner.invoke(autolower, ["HELLO WORLD"])
12
- assert result.exit_code == 0
13
- assert "hello world" in result.output
14
-
15
- # TEST FOR EMPTY INPUT
16
- def test_autolower_cli_empty():
17
- """TEST CLI WITH EMPTY INPUT"""
18
- runner = CliRunner()
19
- result = runner.invoke(autolower, [""])
20
- assert result.exit_code == 0
21
- assert "" in result.output
22
-
23
- # TEST FOR SPECIAL CHARACTERS
24
- def test_autolower_cli_special_chars():
25
- """TEST CLI WITH SPECIAL CHARACTERS"""
26
- runner = CliRunner()
27
- result = runner.invoke(autolower, ["HELLO@WORLD.COM"])
28
- assert result.exit_code == 0
29
- assert "hello@world.com" in result.output
30
-
31
- # TEST FOR UNICODE CHARACTERS
32
- def test_autolower_cli_unicode():
33
- """TEST CLI WITH UNICODE CHARACTERS"""
34
- runner = CliRunner()
35
- result = runner.invoke(autolower, ["HÉLLO WÖRLD"])
36
- assert result.exit_code == 0
37
- assert "héllo wörld" in result.output
38
-
39
- # TEST FOR MULTIPLE ARGUMENTS
40
- def test_autolower_cli_multiple_args():
41
- """TEST CLI WITH MULTIPLE ARGUMENTS"""
42
- runner = CliRunner()
43
- result = runner.invoke(autolower, ["HELLO", "WORLD"])
44
- assert result.exit_code == 0
45
- # SHOULD ONLY PROCESS FIRST ARGUMENT
46
- assert "hello" in result.output
@@ -1,3 +0,0 @@
1
- from .core import SpellChecker
2
-
3
- __all__ = ['SpellChecker']