Open-AutoTools 0.0.2.post2__py3-none-any.whl → 0.0.3rc1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: Open-AutoTools
3
- Version: 0.0.2.post2
3
+ Version: 0.0.3rc1
4
4
  Summary: A suite of automated tools accessible via CLI with a simple `autotools` command
5
5
  Home-page: https://github.com/BabylooPro/Open-AutoTools
6
6
  Author: BabylooPro
@@ -18,14 +18,16 @@ Requires-Dist: charset-normalizer==3.3.2
18
18
  Requires-Dist: click==8.1.3
19
19
  Requires-Dist: cryptography==42.0.2
20
20
  Requires-Dist: idna==3.6
21
- Requires-Dist: importlib-metadata==7.0.1
21
+ Requires-Dist: importlib-metadata>=7.0.1
22
22
  Requires-Dist: joblib==1.3.2
23
23
  Requires-Dist: Levenshtein==0.25.0
24
24
  Requires-Dist: mutagen==1.47.0
25
+ Requires-Dist: packaging>=23.0
25
26
  Requires-Dist: platformdirs==4.2.0
26
27
  Requires-Dist: pycryptodomex==3.20.0
27
28
  Requires-Dist: pyperclip==1.8.2
28
29
  Requires-Dist: python-Levenshtein==0.25.0
30
+ Requires-Dist: python-dotenv>=1.0.0
29
31
  Requires-Dist: rapidfuzz==3.6.1
30
32
  Requires-Dist: regex==2023.12.25
31
33
  Requires-Dist: requests>=2.32.2
@@ -44,6 +46,12 @@ Requires-Dist: netifaces>=0.11.0
44
46
  Requires-Dist: speedtest-cli>=2.1.3
45
47
  Requires-Dist: psutil>=5.9.0
46
48
  Requires-Dist: setuptools>=40.8.0
49
+ Requires-Dist: language-tool-python>=2.7.1
50
+ Requires-Dist: spacy>=3.7.2
51
+ Requires-Dist: beautifulsoup4>=4.12.0
52
+ Provides-Extra: test
53
+ Requires-Dist: pytest>=7.4.0; extra == "test"
54
+ Requires-Dist: pytest-cov>=4.1.0; extra == "test"
47
55
  Dynamic: author
48
56
  Dynamic: author-email
49
57
  Dynamic: classifier
@@ -51,6 +59,7 @@ Dynamic: description
51
59
  Dynamic: description-content-type
52
60
  Dynamic: home-page
53
61
  Dynamic: project-url
62
+ Dynamic: provides-extra
54
63
  Dynamic: requires-dist
55
64
  Dynamic: requires-python
56
65
  Dynamic: summary
@@ -164,6 +173,22 @@ These examples demonstrate how the terminal will display the results after execu
164
173
  - `--detect`: Show detected source language
165
174
  - `--list-languages`: Show all supported language codes and names
166
175
 
176
+ ### AutoSpell (unreleased)
177
+
178
+ - **Description:** Checks and corrects spelling in text with multi-language support.
179
+ - **Usage:**
180
+ ```
181
+ ~ ❯ autospell "Your text with misspellings"
182
+ ~ ❯ autospell --lang fr "Votre texte avec des fautes"
183
+ ~ ❯ autospell --file document.txt
184
+ ```
185
+ - **Options:**
186
+ - `--lang`: Language code (default: en)
187
+ - `--file`: Input from file
188
+ - `--copy`: Copy corrected text to clipboard
189
+ - `--suggest`: Show alternative suggestions
190
+ - `--interactive`: Interactive correction mode
191
+
167
192
  ### AutoDownload
168
193
 
169
194
  - **Description:** Downloads videos from YouTube and files from other sources.
@@ -0,0 +1,31 @@
1
+ autotools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ autotools/cli.py,sha256=YJ_0Dq7t97SPkmmRSvqFuBkOVsh2UcnNcS8wdNSoESg,24389
3
+ autotools/autocaps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ autotools/autocaps/core.py,sha256=NnOacVp0kMoq__KHWi5UMcApSuq6Iyo5bFxN40dRw7U,253
5
+ autotools/autocaps/tests/__init__.py,sha256=CckydfM7SZdXtW3pLgAeRdrC60sovNx_v59nyFvslFo,23
6
+ autotools/autocaps/tests/test_autocaps_core.py,sha256=fzpci_sK7L1fSf_IJ1paJ__bmnHwC9OUOD7ftd3w07c,1672
7
+ autotools/autocaps/tests/test_autocaps_integration.py,sha256=Qe2hzVEvzf0-INp14oTTrHi0RiRDCE2fxo9abVNcd_E,1435
8
+ autotools/autodownload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ autotools/autodownload/core.py,sha256=xmQSEEi3UYPkbbwsL-H4vGKcpqLCkwhIYlZxDWrIEpI,8266
10
+ autotools/autoip/__init__.py,sha256=T_5hz9G4reFPXDucdzRoMFPYlAKwTPt9TejOpkRPgn0,23
11
+ autotools/autoip/core.py,sha256=Q3dzLstZQruwYkSbCSlKQNmKVGCyNpo1DGst5VFtHLU,10123
12
+ autotools/autoip/tests/__init__.py,sha256=CckydfM7SZdXtW3pLgAeRdrC60sovNx_v59nyFvslFo,23
13
+ autotools/autoip/tests/test_autoip_core.py,sha256=Q8865qqhopcGBzS4mIlDlEzxu-mTIbZxpgJyzIyuQXc,2153
14
+ autotools/autoip/tests/test_autoip_integration.py,sha256=-vS2gnY8ZfT-tfY2FRbUtTzY0lcIBtVZHbPbWsKyueo,2746
15
+ autotools/autolower/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ autotools/autolower/core.py,sha256=vjM2ognA3tDCbv10a9vta9WPuAiqTPjOXZ1JHL_b-nk,260
17
+ autotools/autolower/tests/__init__.py,sha256=CckydfM7SZdXtW3pLgAeRdrC60sovNx_v59nyFvslFo,23
18
+ autotools/autolower/tests/test_autolower_core.py,sha256=ChkS3qZgXz75iLfC9EXVH_kMd-sjaxpRKFjaxKoBnxo,1694
19
+ autotools/autolower/tests/test_autolower_integration.py,sha256=M2yN1Ym7kGulys62-IwKq-uWn7CFvI3sCnoo-e3CTaA,1446
20
+ autotools/autopassword/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
21
+ autotools/autopassword/core.py,sha256=GQrd-QGWpgxuq6Nf28URcTZRku8Gji1NfpbecXAsIF0,3146
22
+ autotools/autospell/__init__.py,sha256=jkpkiE7pksBgllXKfkNpYYvqtlm8vN0h4kXnQOqcb_U,60
23
+ autotools/autospell/core.py,sha256=WPvi9Xs6uF3dte_g2I9oHfTjCV1-NasrJElLP9bbC8U,8103
24
+ autotools/autotranslate/__init__.py,sha256=6BxuZqhyQhfsZ5x7DkB1BAEpC08GT_5l5bl0AY_eLpU,64
25
+ autotools/autotranslate/core.py,sha256=H2f90IWr_jNGiJD3XAv-20i5sRGM-VDYWrYt65EDEkI,1836
26
+ Open_AutoTools-0.0.3rc1.dist-info/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
27
+ Open_AutoTools-0.0.3rc1.dist-info/METADATA,sha256=Vvbj28d0I4k0RdUeBE6v2lxmkvr5UxV89nznLpU9bVs,9120
28
+ Open_AutoTools-0.0.3rc1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
29
+ Open_AutoTools-0.0.3rc1.dist-info/entry_points.txt,sha256=QLIsUk6vHo0wAYDk1K74kIuYunJMwWe2xbwQhJXLoKo,312
30
+ Open_AutoTools-0.0.3rc1.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
31
+ Open_AutoTools-0.0.3rc1.dist-info/RECORD,,
@@ -4,5 +4,6 @@ autodownload = autotools.cli:autodownload
4
4
  autoip = autotools.cli:autoip
5
5
  autolower = autotools.cli:autolower
6
6
  autopassword = autotools.cli:autopassword
7
- autotools = autotools.cli:autotools
7
+ autospell = autotools.cli:autospell
8
+ autotools = autotools.cli:cli
8
9
  autotranslate = autotools.cli:autotranslate
@@ -0,0 +1 @@
1
+ # INIT FILE FOR TESTS
@@ -0,0 +1,45 @@
1
+ import pytest
2
+ from autotools.autocaps.core import autocaps_transform
3
+
4
+ # UNIT TESTS
5
+
6
+ # TEST FOR BASIC STRING TRANSFORMATION
7
+ def test_autocaps_transform_basic():
8
+ """TEST BASIC STRING TRANSFORMATION"""
9
+ assert autocaps_transform("hello") == "HELLO"
10
+ assert autocaps_transform("Hello World") == "HELLO WORLD"
11
+ assert autocaps_transform("123") == "123"
12
+
13
+ # TEST FOR EMPTY STRING
14
+ def test_autocaps_transform_empty():
15
+ """TEST EMPTY STRING"""
16
+ assert autocaps_transform("") == ""
17
+
18
+ # TEST FOR SPECIAL CHARACTERS
19
+ def test_autocaps_transform_special_chars():
20
+ """TEST STRING WITH SPECIAL CHARACTERS"""
21
+ assert autocaps_transform("hello@world.com") == "HELLO@WORLD.COM"
22
+ assert autocaps_transform("hello-world!") == "HELLO-WORLD!"
23
+
24
+ # TEST FOR MIXED CASE STRING
25
+ def test_autocaps_transform_mixed_case():
26
+ """TEST MIXED CASE STRING"""
27
+ assert autocaps_transform("HeLLo WoRLD") == "HELLO WORLD"
28
+
29
+ # TEST FOR WHITESPACE
30
+ def test_autocaps_transform_whitespace():
31
+ """TEST STRING WITH WHITESPACE"""
32
+ assert autocaps_transform(" hello world ") == " HELLO WORLD "
33
+ assert autocaps_transform("\thello\nworld") == "\tHELLO\nWORLD"
34
+
35
+ # TEST FOR NUMBERS
36
+ def test_autocaps_transform_numbers():
37
+ """TEST STRING WITH NUMBERS"""
38
+ assert autocaps_transform("hello123world") == "HELLO123WORLD"
39
+ assert autocaps_transform("123hello456world789") == "123HELLO456WORLD789"
40
+
41
+ # TEST FOR UNICODE CHARACTERS
42
+ def test_autocaps_transform_unicode():
43
+ """TEST UNICODE CHARACTERS"""
44
+ assert autocaps_transform("héllo wörld") == "HÉLLO WÖRLD"
45
+ assert autocaps_transform("こんにちは") == "こんにちは" # JAPANESE SHOULD REMAIN UNCHANGED
@@ -0,0 +1,46 @@
1
+ import pytest
2
+ from click.testing import CliRunner
3
+ from autotools.cli import autocaps
4
+
5
+ # INTEGRATION TESTS
6
+
7
+ # TEST FOR BASIC CLI FUNCTIONALITY
8
+ def test_autocaps_cli_basic():
9
+ """TEST BASIC CLI FUNCTIONALITY"""
10
+ runner = CliRunner()
11
+ result = runner.invoke(autocaps, ["hello world"])
12
+ assert result.exit_code == 0
13
+ assert "HELLO WORLD" in result.output
14
+
15
+ # TEST FOR EMPTY INPUT
16
+ def test_autocaps_cli_empty():
17
+ """TEST CLI WITH EMPTY INPUT"""
18
+ runner = CliRunner()
19
+ result = runner.invoke(autocaps, [""])
20
+ assert result.exit_code == 0
21
+ assert "" in result.output
22
+
23
+ # TEST FOR SPECIAL CHARACTERS
24
+ def test_autocaps_cli_special_chars():
25
+ """TEST CLI WITH SPECIAL CHARACTERS"""
26
+ runner = CliRunner()
27
+ result = runner.invoke(autocaps, ["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_autocaps_cli_unicode():
33
+ """TEST CLI WITH UNICODE CHARACTERS"""
34
+ runner = CliRunner()
35
+ result = runner.invoke(autocaps, ["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_autocaps_cli_multiple_args():
41
+ """TEST CLI WITH MULTIPLE ARGUMENTS"""
42
+ runner = CliRunner()
43
+ result = runner.invoke(autocaps, ["hello", "world"])
44
+ assert result.exit_code == 0
45
+ # SHOULD ONLY PROCESS FIRST ARGUMENT
46
+ assert "HELLO" in result.output
autotools/autoip/core.py CHANGED
@@ -1,5 +1,7 @@
1
1
  import socket
2
2
  import requests
3
+ import json
4
+ import ipaddress
3
5
  import netifaces
4
6
  import time
5
7
  import speedtest
@@ -125,94 +127,185 @@ def run_speedtest():
125
127
  print(f"\nSpeed test failed: {str(e)}")
126
128
  return False
127
129
 
128
- def run(test=False, speed=False, monitor=False, ports=False, dns=False, location=False, no_ip=False):
129
- """MAIN FUNCTION"""
130
- # GET LOCAL AND PUBLIC IPS
131
- local = get_local_ips()
132
- public = get_public_ips()
130
+ # GET PUBLIC IP ADDRESS USING IPIFY API
131
+ def get_public_ip():
132
+ """GET PUBLIC IP ADDRESS USING IPIFY API"""
133
+ try:
134
+ response = requests.get('https://api.ipify.org')
135
+ return response.text
136
+ except requests.RequestException:
137
+ # FALLBACK TO ANOTHER SERVICE IF IPIFY FAILS
138
+ try:
139
+ response = requests.get('https://api.ipapi.com/api/check')
140
+ return response.json()['ip']
141
+ except:
142
+ return None
143
+
144
+ # GET LOCAL IP ADDRESS
145
+ def get_local_ip():
146
+ """GET LOCAL IP ADDRESS"""
147
+ try:
148
+ # GET DEFAULT INTERFACE
149
+ gateways = netifaces.gateways()
150
+ default_interface = gateways['default'][netifaces.AF_INET][1]
151
+
152
+ # GET IP FROM DEFAULT INTERFACE
153
+ addrs = netifaces.ifaddresses(default_interface)
154
+ return addrs[netifaces.AF_INET][0]['addr']
155
+ except:
156
+ # FALLBACK METHOD
157
+ try:
158
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
159
+ s.connect(("8.8.8.8", 80))
160
+ ip = s.getsockname()[0]
161
+ s.close()
162
+ return ip
163
+ except:
164
+ return None
165
+
166
+ # GET IP INFORMATION USING IPAPI.CO
167
+ def get_ip_info(ip=None):
168
+ """GET IP INFORMATION USING IPAPI.CO
169
+
170
+ Args:
171
+ ip (str, optional): IP address to get info for. If None, uses current IP.
172
+
173
+ Returns:
174
+ dict: Dictionary containing IP information
175
+
176
+ Raises:
177
+ ValueError: If IP is invalid or private
178
+ """
179
+ if ip:
180
+ # VALIDATE IP
181
+ try:
182
+ ip_obj = ipaddress.ip_address(ip)
183
+ if ip_obj.is_private:
184
+ raise ValueError("Cannot get info for private IP addresses")
185
+ except ValueError as e:
186
+ raise ValueError(f"Invalid IP address: {str(e)}")
187
+
188
+ try:
189
+ # USE IPAPI.CO FOR IP INFO
190
+ url = f'https://ipapi.co/{ip}/json' if ip else 'https://ipapi.co/json'
191
+ response = requests.get(url)
192
+ data = response.json()
193
+
194
+ if 'error' in data:
195
+ raise ValueError(f"Error getting IP info: {data['error']}")
196
+
197
+ return data
198
+ except requests.RequestException as e:
199
+ raise ValueError(f"Error connecting to IP info service: {str(e)}")
200
+
201
+ # MAIN FUNCTION TO RUN IP TOOLS
202
+ def run(test=False, speed=False, monitor=False, interval=1, ports=False, dns=False, location=False, no_ip=False):
203
+ """MAIN FUNCTION TO RUN IP TOOLS
204
+
205
+ Args:
206
+ test (bool): Run connectivity tests
207
+ speed (bool): Run speed test
208
+ monitor (bool): Monitor network traffic
209
+ interval (int): Monitoring interval in seconds
210
+ ports (bool): Check common ports status
211
+ dns (bool): Show DNS servers
212
+ location (bool): Show IP location info
213
+ no_ip (bool): Hide IP addresses
214
+ """
215
+ output = []
133
216
 
134
- # DISPLAY IPS IF NOT HIDDEN
217
+ # GET IP ADDRESSES IF NOT HIDDEN
135
218
  if not no_ip:
136
- print("\nLocal IPs:")
137
- if local['ipv4']:
138
- for ip in local['ipv4']:
139
- print(f"IPv4: {ip}")
219
+ local_ips = get_local_ips()
220
+ public_ips = get_public_ips()
221
+
222
+ output.append("\nLocal IPs:")
223
+ if local_ips['ipv4']:
224
+ for ip in local_ips['ipv4']:
225
+ output.append(f"IPv4: {ip}")
140
226
  else:
141
- print("IPv4: Not available")
227
+ output.append("IPv4: Not available")
142
228
 
143
- if local['ipv6']:
144
- for ip in local['ipv6']:
145
- print(f"IPv6: {ip}")
229
+ if local_ips['ipv6']:
230
+ for ip in local_ips['ipv6']:
231
+ output.append(f"IPv6: {ip}")
146
232
  else:
147
- print("IPv6: Not available")
233
+ output.append("IPv6: Not available")
148
234
 
149
- print("\nPublic IPs:")
150
- print(f"IPv4: {public['ipv4'] or 'Not available'}")
151
- print(f"IPv6: {public['ipv6'] or 'Not available'}")
235
+ output.append("\nPublic IPs:")
236
+ output.append(f"IPv4: {public_ips['ipv4'] or 'Not available'}")
237
+ output.append(f"IPv6: {public_ips['ipv6'] or 'Not available'}")
152
238
 
153
239
  # RUN CONNECTIVITY TESTS IF REQUESTED
154
240
  if test:
155
- print("\nConnectivity Tests:")
241
+ output.append("\nConnectivity Tests:")
156
242
  results = test_connectivity()
157
243
  for name, success, latency in results:
158
244
  status = f"✓ {latency}ms" if success else "✗ Failed"
159
- print(f"{name:<15} {status}")
245
+ output.append(f"{name:<15} {status}")
160
246
 
161
247
  # RUN SPEED TEST IF REQUESTED
162
248
  if speed:
163
- run_speedtest()
249
+ output.append("\nRunning speed test...")
250
+ if run_speedtest():
251
+ output.append("Speed test completed successfully")
252
+ else:
253
+ output.append("Speed test failed")
164
254
 
165
255
  # DISPLAY LOCATION INFO IF REQUESTED
166
256
  if location:
167
257
  try:
168
- loc = requests.get('https://ipapi.co/json/').json()
169
- print("\nLocation Info:")
170
- print(f"City: {loc.get('city', 'Unknown')}")
171
- print(f"Region: {loc.get('region', 'Unknown')}")
172
- print(f"Country: {loc.get('country_name', 'Unknown')}")
173
- print(f"ISP: {loc.get('org', 'Unknown')}")
174
- except:
175
- print("\nLocation lookup failed")
258
+ loc = get_ip_info()
259
+ output.append("\nLocation Info:")
260
+ output.append(f"City: {loc.get('city', 'Unknown')}")
261
+ output.append(f"Region: {loc.get('region', 'Unknown')}")
262
+ output.append(f"Country: {loc.get('country', 'Unknown')}")
263
+ output.append(f"ISP: {loc.get('org', 'Unknown')}")
264
+ except Exception as e:
265
+ output.append(f"\nLocation lookup failed: {str(e)}")
176
266
 
177
267
  # DISPLAY DNS SERVERS IF REQUESTED
178
268
  if dns:
179
- print("\nDNS Servers:")
269
+ output.append("\nDNS Servers:")
180
270
  try:
181
271
  with open('/etc/resolv.conf', 'r') as f:
182
272
  for line in f:
183
273
  if 'nameserver' in line:
184
- print(f"DNS: {line.split()[1]}")
274
+ output.append(f"DNS: {line.split()[1]}")
185
275
  except:
186
- print("Could not read DNS configuration")
276
+ output.append("Could not read DNS configuration")
187
277
 
188
278
  # CHECK COMMON PORTS IF REQUESTED
189
279
  if ports:
190
280
  common_ports = [80, 443, 22, 21, 25, 3306]
191
- print("\nCommon Ports Status (localhost):")
281
+ output.append("\nCommon Ports Status (localhost):")
192
282
  for port in common_ports:
193
283
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
194
284
  result = sock.connect_ex(('127.0.0.1', port))
195
285
  status = "Open" if result == 0 else "Closed"
196
- print(f"Port {port}: {status}")
286
+ output.append(f"Port {port}: {status}")
197
287
  sock.close()
198
288
 
199
289
  # MONITOR NETWORK TRAFFIC IF REQUESTED
200
290
  if monitor:
201
- print("\nNetwork Monitor (Press Ctrl+C to stop):")
291
+ output.append("\nNetwork Monitor (Press Ctrl+C to stop):")
202
292
  try:
203
293
  prev_bytes_sent = psutil.net_io_counters().bytes_sent
204
294
  prev_bytes_recv = psutil.net_io_counters().bytes_recv
205
295
  while True:
206
- time.sleep(1)
296
+ time.sleep(interval)
207
297
  bytes_sent = psutil.net_io_counters().bytes_sent
208
298
  bytes_recv = psutil.net_io_counters().bytes_recv
209
299
 
210
- upload_speed = (bytes_sent - prev_bytes_sent) / 1024 # KB/s
211
- download_speed = (bytes_recv - prev_bytes_recv) / 1024 # KB/s
300
+ # CALCULATE UPLOAD AND DOWNLOAD SPEEDS
301
+ upload_speed = (bytes_sent - prev_bytes_sent) / (1024 * interval)
302
+ download_speed = (bytes_recv - prev_bytes_recv) / (1024 * interval)
212
303
 
213
- print(f"\rUp: {upload_speed:.2f} KB/s | Down: {download_speed:.2f} KB/s", end='')
304
+ output.append(f"\rUp: {upload_speed:.2f} KB/s | Down: {download_speed:.2f} KB/s")
214
305
 
215
306
  prev_bytes_sent = bytes_sent
216
307
  prev_bytes_recv = bytes_recv
217
308
  except KeyboardInterrupt:
218
- print("\nMonitoring stopped")
309
+ output.append("\nMonitoring stopped")
310
+
311
+ return "\n".join(output)
@@ -0,0 +1 @@
1
+ # INIT FILE FOR TESTS
@@ -0,0 +1,72 @@
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)
@@ -0,0 +1,92 @@
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
@@ -0,0 +1 @@
1
+ # INIT FILE FOR TESTS
@@ -0,0 +1,45 @@
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