v2kit 0.3__tar.gz → 0.4__tar.gz

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 (43) hide show
  1. {v2kit-0.3 → v2kit-0.4}/CHANGELOG.md +9 -1
  2. {v2kit-0.3 → v2kit-0.4}/PKG-INFO +14 -5
  3. {v2kit-0.3 → v2kit-0.4}/README.md +3 -2
  4. {v2kit-0.3 → v2kit-0.4}/SECURITY.md +2 -2
  5. {v2kit-0.3 → v2kit-0.4}/setup.py +3 -2
  6. {v2kit-0.3 → v2kit-0.4}/tests/test_errors.py +25 -3
  7. {v2kit-0.3 → v2kit-0.4}/tests/test_functions.py +11 -1
  8. v2kit-0.4/tests/test_http.py +194 -0
  9. v2kit-0.4/tests/test_shadowsocks.py +196 -0
  10. v2kit-0.4/tests/test_socks.py +192 -0
  11. v2kit-0.4/tests/test_trojan.py +161 -0
  12. v2kit-0.4/tests/test_vless.py +169 -0
  13. v2kit-0.4/tests/test_vmess.py +163 -0
  14. {v2kit-0.3 → v2kit-0.4}/v2kit/__init__.py +5 -2
  15. {v2kit-0.3 → v2kit-0.4}/v2kit/functions.py +9 -0
  16. {v2kit-0.3 → v2kit-0.4}/v2kit/models/__init__.py +2 -1
  17. {v2kit-0.3 → v2kit-0.4}/v2kit/models/base.py +2 -2
  18. v2kit-0.4/v2kit/models/http.py +166 -0
  19. {v2kit-0.3 → v2kit-0.4}/v2kit/params.py +2 -1
  20. {v2kit-0.3 → v2kit-0.4}/v2kit/parsers.py +22 -4
  21. {v2kit-0.3 → v2kit-0.4}/v2kit.egg-info/PKG-INFO +14 -5
  22. {v2kit-0.3 → v2kit-0.4}/v2kit.egg-info/SOURCES.txt +2 -0
  23. v2kit-0.3/tests/test_shadowsocks.py +0 -17
  24. v2kit-0.3/tests/test_socks.py +0 -69
  25. v2kit-0.3/tests/test_trojan.py +0 -17
  26. v2kit-0.3/tests/test_vless.py +0 -58
  27. v2kit-0.3/tests/test_vmess.py +0 -32
  28. {v2kit-0.3 → v2kit-0.4}/AUTHORS.md +0 -0
  29. {v2kit-0.3 → v2kit-0.4}/LICENSE +0 -0
  30. {v2kit-0.3 → v2kit-0.4}/MANIFEST.in +0 -0
  31. {v2kit-0.3 → v2kit-0.4}/requirements-dev.txt +0 -0
  32. {v2kit-0.3 → v2kit-0.4}/setup.cfg +0 -0
  33. {v2kit-0.3 → v2kit-0.4}/v2kit/__main__.py +0 -0
  34. {v2kit-0.3 → v2kit-0.4}/v2kit/errors.py +0 -0
  35. {v2kit-0.3 → v2kit-0.4}/v2kit/models/shadowsocks.py +0 -0
  36. {v2kit-0.3 → v2kit-0.4}/v2kit/models/socks.py +0 -0
  37. {v2kit-0.3 → v2kit-0.4}/v2kit/models/trojan.py +0 -0
  38. {v2kit-0.3 → v2kit-0.4}/v2kit/models/vless.py +0 -0
  39. {v2kit-0.3 → v2kit-0.4}/v2kit/models/vmess.py +0 -0
  40. {v2kit-0.3 → v2kit-0.4}/v2kit/utils.py +0 -0
  41. {v2kit-0.3 → v2kit-0.4}/v2kit/validators.py +0 -0
  42. {v2kit-0.3 → v2kit-0.4}/v2kit.egg-info/dependency_links.txt +0 -0
  43. {v2kit-0.3 → v2kit-0.4}/v2kit.egg-info/top_level.txt +0 -0
@@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
+ ## [0.4] - 2026-07-02
9
+ ### Added
10
+ - `HttpConfig` class
11
+ ### Changed
12
+ - `parse` function modified
13
+ - `README.md` updated
14
+ - Test system modified
8
15
  ## [0.3] - 2026-06-16
9
16
  ### Added
10
17
  - Logo
@@ -43,7 +50,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
43
50
  - `encode_subscription` function
44
51
  - `decode_subscription` function
45
52
 
46
- [Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.3...dev
53
+ [Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.4...dev
54
+ [0.4]: https://github.com/sepandhaghighi/v2kit/compare/v0.3...v0.4
47
55
  [0.3]: https://github.com/sepandhaghighi/v2kit/compare/v0.2...v0.3
48
56
  [0.2]: https://github.com/sepandhaghighi/v2kit/compare/v0.1...v0.2
49
57
  [0.1]: https://github.com/sepandhaghighi/v2kit/compare/bb5a2cb...v0.1
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: v2kit
3
- Version: 0.3
3
+ Version: 0.4
4
4
  Summary: V2Kit: A Lightweight Toolkit for V2Ray Config Manipulation
5
5
  Home-page: https://github.com/sepandhaghighi/v2kit
6
- Download-URL: https://github.com/sepandhaghighi/v2kit/tarball/v0.3
6
+ Download-URL: https://github.com/sepandhaghighi/v2kit/tarball/v0.4
7
7
  Author: Sepand Haghighi
8
8
  Author-email: me@sepand.tech
9
9
  License: MIT
@@ -96,13 +96,13 @@ V2Kit is a lightweight and extensible Python toolkit for working with V2Ray prox
96
96
  ## Installation
97
97
 
98
98
  ### Source Code
99
- - Download [Version 0.3](https://github.com/sepandhaghighi/v2kit/archive/v0.3.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
99
+ - Download [Version 0.4](https://github.com/sepandhaghighi/v2kit/archive/v0.4.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
100
100
  - `pip install .`
101
101
 
102
102
  ### PyPI
103
103
 
104
104
  - Check [Python Packaging User Guide](https://packaging.python.org/installing/)
105
- - `pip install v2kit==0.3`
105
+ - `pip install v2kit==0.4`
106
106
 
107
107
  ## Supported Protocols
108
108
 
@@ -115,6 +115,7 @@ V2Kit currently supports the following protocols:
115
115
  | Trojan | ✅ | ✅ | ✅ | ✅ |
116
116
  | Shadowsocks | ✅ | ✅ | ✅ | ✅ |
117
117
  | SOCKS | ✅ | ✅ | ✅ | ✅ |
118
+ | HTTP | ✅ | ✅ | ✅ | ✅ |
118
119
 
119
120
 
120
121
  ## Usage
@@ -210,6 +211,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
210
211
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
211
212
 
212
213
  ## [Unreleased]
214
+ ## [0.4] - 2026-07-02
215
+ ### Added
216
+ - `HttpConfig` class
217
+ ### Changed
218
+ - `parse` function modified
219
+ - `README.md` updated
220
+ - Test system modified
213
221
  ## [0.3] - 2026-06-16
214
222
  ### Added
215
223
  - Logo
@@ -248,7 +256,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
248
256
  - `encode_subscription` function
249
257
  - `decode_subscription` function
250
258
 
251
- [Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.3...dev
259
+ [Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.4...dev
260
+ [0.4]: https://github.com/sepandhaghighi/v2kit/compare/v0.3...v0.4
252
261
  [0.3]: https://github.com/sepandhaghighi/v2kit/compare/v0.2...v0.3
253
262
  [0.2]: https://github.com/sepandhaghighi/v2kit/compare/v0.1...v0.2
254
263
  [0.1]: https://github.com/sepandhaghighi/v2kit/compare/bb5a2cb...v0.1
@@ -51,13 +51,13 @@ V2Kit is a lightweight and extensible Python toolkit for working with V2Ray prox
51
51
  ## Installation
52
52
 
53
53
  ### Source Code
54
- - Download [Version 0.3](https://github.com/sepandhaghighi/v2kit/archive/v0.3.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
54
+ - Download [Version 0.4](https://github.com/sepandhaghighi/v2kit/archive/v0.4.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
55
55
  - `pip install .`
56
56
 
57
57
  ### PyPI
58
58
 
59
59
  - Check [Python Packaging User Guide](https://packaging.python.org/installing/)
60
- - `pip install v2kit==0.3`
60
+ - `pip install v2kit==0.4`
61
61
 
62
62
  ## Supported Protocols
63
63
 
@@ -70,6 +70,7 @@ V2Kit currently supports the following protocols:
70
70
  | Trojan | ✅ | ✅ | ✅ | ✅ |
71
71
  | Shadowsocks | ✅ | ✅ | ✅ | ✅ |
72
72
  | SOCKS | ✅ | ✅ | ✅ | ✅ |
73
+ | HTTP | ✅ | ✅ | ✅ | ✅ |
73
74
 
74
75
 
75
76
  ## Usage
@@ -4,8 +4,8 @@
4
4
 
5
5
  | Version | Supported |
6
6
  | ------------- | ------------------ |
7
- | 0.3 | :white_check_mark: |
8
- | < 0.3 | :x: |
7
+ | 0.4 | :white_check_mark: |
8
+ | < 0.4 | :x: |
9
9
 
10
10
  ## Reporting a Vulnerability
11
11
 
@@ -2,6 +2,7 @@
2
2
  """Setup module."""
3
3
  from setuptools import setup
4
4
 
5
+
5
6
  def read_description() -> str:
6
7
  """Read README.md and CHANGELOG.md."""
7
8
  try:
@@ -22,7 +23,7 @@ def read_description() -> str:
22
23
  setup(
23
24
  name='v2kit',
24
25
  packages=['v2kit', 'v2kit.models'],
25
- version='0.3',
26
+ version='0.4',
26
27
  description='V2Kit: A Lightweight Toolkit for V2Ray Config Manipulation',
27
28
  long_description=read_description(),
28
29
  long_description_content_type='text/markdown',
@@ -30,7 +31,7 @@ setup(
30
31
  author='Sepand Haghighi',
31
32
  author_email='me@sepand.tech',
32
33
  url='https://github.com/sepandhaghighi/v2kit',
33
- download_url='https://github.com/sepandhaghighi/v2kit/tarball/v0.3',
34
+ download_url='https://github.com/sepandhaghighi/v2kit/tarball/v0.4',
34
35
  keywords='v2ray v2ray-config v2ray-tools vmess vless trojan shadowsocks proxy subscription network',
35
36
  project_urls={
36
37
  'Source': 'https://github.com/sepandhaghighi/v2kit'},
@@ -7,10 +7,12 @@ from v2kit import V2kitError, V2kitValidationError, V2kitParseError
7
7
  from v2kit.validators import _validate_uri
8
8
 
9
9
 
10
- INVALID_PROTOCOL = "http://example.com"
10
+ INVALID_PROTOCOL = "ftp://example.com"
11
11
 
12
12
  INVALID_VMESS = "vmess://invalid-base64"
13
13
 
14
+ INVALID_SHADOWSOCKS = "ss://invalid-base64@example.com:8388#ss-test"
15
+
14
16
  VALID_VLESS = (
15
17
  "vless://1c4b4bca-e3ff-4ca8-a062-6f399ad3cf45@example.com:443"
16
18
  "?security=tls#test"
@@ -61,7 +63,7 @@ def test_relabel_non_string_label():
61
63
  relabel(VALID_VLESS, 123)
62
64
 
63
65
 
64
- def test_encode_subscription_invalid_config():
66
+ def test_encode_subscription_invalid_config1():
65
67
  configs = [
66
68
  VALID_VLESS,
67
69
  "invalid-config",
@@ -71,6 +73,16 @@ def test_encode_subscription_invalid_config():
71
73
  encode_subscription(configs)
72
74
 
73
75
 
76
+ def test_encode_subscription_invalid_config2():
77
+ configs = [
78
+ VALID_VLESS,
79
+ 1,
80
+ ]
81
+
82
+ with pytest.raises(V2kitValidationError):
83
+ encode_subscription(configs)
84
+
85
+
74
86
  def test_decode_subscription_non_string():
75
87
  with pytest.raises(V2kitValidationError):
76
88
  decode_subscription(123)
@@ -109,7 +121,17 @@ def test_parse_invalid_uri():
109
121
 
110
122
  def test_parse_unsupported_protocol():
111
123
  with pytest.raises(V2kitParseError):
112
- parse("http://example.com")
124
+ parse(INVALID_PROTOCOL)
125
+
126
+
127
+ def test_parse_invalid_vmess():
128
+ with pytest.raises(V2kitParseError):
129
+ parse(INVALID_VMESS)
130
+
131
+
132
+ def test_parse_invalid_shadowsocks():
133
+ with pytest.raises(V2kitParseError):
134
+ parse(INVALID_SHADOWSOCKS)
113
135
 
114
136
 
115
137
  def test_vless_invalid_uuid():
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  import json
4
- from v2kit import is_vmess, is_vless, is_trojan, is_shadowsocks, is_socks, parse
4
+ from v2kit import is_vmess, is_vless, is_trojan, is_shadowsocks, is_socks, is_http, parse
5
5
  from v2kit import relabel, encode_subscription, decode_subscription
6
6
  from v2kit import VMESSConfig, VLESSConfig, TrojanConfig, ShadowsocksConfig, SocksConfig
7
7
  from v2kit.utils import _encode_base64
@@ -37,6 +37,8 @@ SHADOWSOCKS_CONFIG = "ss://YWVzLTI1Ni1nY206cGFzc3dvcmQ=@example.com:8388#ss-test
37
37
 
38
38
  SOCKS_CONFIG = "socks://user:password@example.com:1080#socks-test"
39
39
 
40
+ HTTP_CONFIG = "http://user@example.com:1080#test"
41
+
40
42
 
41
43
  def test_is_vmess():
42
44
  assert is_vmess(VMESS_CONFIG) is True
@@ -54,6 +56,10 @@ def test_is_shadowsocks():
54
56
  assert is_shadowsocks(SHADOWSOCKS_CONFIG) is True
55
57
 
56
58
 
59
+ def test_is_http():
60
+ assert is_http(HTTP_CONFIG) is True
61
+
62
+
57
63
  def test_is_vmess_negative():
58
64
  assert is_vmess(VLESS_CONFIG) is False
59
65
 
@@ -74,6 +80,10 @@ def test_is_shadowsocks_invalid():
74
80
  assert is_shadowsocks("invalid") is False
75
81
 
76
82
 
83
+ def test_is_http_invalid():
84
+ assert is_http("invalid") is False
85
+
86
+
77
87
  def test_is_socks():
78
88
  assert is_socks(SOCKS_CONFIG) is True
79
89
 
@@ -0,0 +1,194 @@
1
+ # -*- coding: utf-8 -*-
2
+ import pytest
3
+ from v2kit import parse
4
+ from v2kit import HttpConfig
5
+
6
+
7
+ def test_defaults():
8
+ config = HttpConfig(
9
+ address="example.com",
10
+ port=1080,
11
+ )
12
+
13
+ assert config.label is None
14
+ assert config.extra == {}
15
+ assert config.username is None
16
+ assert config.password is None
17
+
18
+
19
+ def test_to_dict():
20
+ config = HttpConfig(
21
+ address="example.com",
22
+ port=1080,
23
+ username="user",
24
+ password="password",
25
+ label="test",
26
+ extra={"foo": "bar"},
27
+ )
28
+
29
+ assert config.to_dict() == {
30
+ "protocol": "http",
31
+ "address": "example.com",
32
+ "port": 1080,
33
+ "username": "user",
34
+ "password": "password",
35
+ "extra": {"foo": "bar"},
36
+ "label": "test",
37
+ }
38
+
39
+
40
+ def test_extra():
41
+ config = HttpConfig(
42
+ address="example.com",
43
+ port=1080,
44
+ extra={"foo": "bar"},
45
+ )
46
+
47
+ data = config.to_dict()
48
+
49
+ assert data["extra"]["foo"] == "bar"
50
+
51
+
52
+ def test_update_methods():
53
+ config = HttpConfig(
54
+ address="example.com",
55
+ port=1080,
56
+ )
57
+
58
+ config.update_address("example.org")
59
+ config.update_port(8080)
60
+ config.update_username("user")
61
+ config.update_password("password")
62
+
63
+ assert config.address == "example.org"
64
+ assert config.port == 8080
65
+ assert config.username == "user"
66
+ assert config.password == "password"
67
+
68
+
69
+ def test_update_extra():
70
+ config = HttpConfig(
71
+ address="example.com",
72
+ port=1080,
73
+ )
74
+
75
+ config.update_extra(
76
+ {"foo": "bar"}
77
+ )
78
+
79
+ assert config.extra["foo"] == "bar"
80
+
81
+
82
+ def test_method_chaining():
83
+ config = HttpConfig(
84
+ address="example.com",
85
+ port=1080,
86
+ )
87
+
88
+ config.update_address(
89
+ "example.org"
90
+ ).update_port(
91
+ 8080
92
+ ).update_username(
93
+ "user"
94
+ ).update_password(
95
+ "password"
96
+ )
97
+
98
+ assert config.address == "example.org"
99
+ assert config.port == 8080
100
+ assert config.username == "user"
101
+ assert config.password == "password"
102
+
103
+
104
+ @pytest.mark.parametrize(
105
+ "kwargs",
106
+ [
107
+ {"address": ""},
108
+ {"port": 0},
109
+ {"port": 1.2},
110
+ {"username": ""},
111
+ {"password": ""},
112
+ {"extra": 1},
113
+ ],
114
+ )
115
+ def test_invalid_values(kwargs):
116
+ params = {
117
+ "address": "example.com",
118
+ "port": 1080,
119
+ }
120
+ params.update(kwargs)
121
+
122
+ with pytest.raises(ValueError):
123
+ HttpConfig(**params)
124
+
125
+
126
+ def test_to_uri_roundtrip():
127
+ config = HttpConfig(
128
+ address="example.com",
129
+ port=1080,
130
+ username="user",
131
+ password="password",
132
+ label="test",
133
+ )
134
+
135
+ parsed = parse(config.to_uri())
136
+
137
+ assert parsed == config
138
+
139
+
140
+ def test_equality():
141
+ config1 = HttpConfig(
142
+ address="example.com",
143
+ port=1080,
144
+ username="user",
145
+ password="password",
146
+ )
147
+
148
+ config2 = HttpConfig(
149
+ address="example.com",
150
+ port=1080,
151
+ username="user",
152
+ password="password",
153
+ )
154
+
155
+ config3 = HttpConfig(
156
+ address="example.org",
157
+ port=1080,
158
+ username="user",
159
+ password="password",
160
+ )
161
+
162
+ assert config1 == config2
163
+ assert config1 != config3
164
+ assert config1 != "config1"
165
+
166
+
167
+ def test_to_uri_without_auth():
168
+ config = HttpConfig(
169
+ address="example.com",
170
+ port=1080,
171
+ label="test",
172
+ )
173
+
174
+ assert config.to_uri() == "http://example.com:1080#test"
175
+
176
+
177
+ def test_to_uri_username_only():
178
+ config = HttpConfig(
179
+ address="example.com",
180
+ port=1080,
181
+ username="user",
182
+ label="test",
183
+ )
184
+
185
+ assert config.to_uri() == "http://user@example.com:1080#test"
186
+
187
+
188
+ def test_repr():
189
+ config = HttpConfig(
190
+ address="example.com",
191
+ port=1080,
192
+ )
193
+
194
+ assert repr(config) == "HttpConfig(protocol=<Protocol.HTTP: 'http'>, label=None)"
@@ -0,0 +1,196 @@
1
+ # -*- coding: utf-8 -*-
2
+ import pytest
3
+ from v2kit import parse
4
+ from v2kit import ShadowsocksConfig
5
+
6
+
7
+ def test_defaults():
8
+ config = ShadowsocksConfig(
9
+ encryption="aes-256-gcm",
10
+ password="password",
11
+ address="example.com",
12
+ port=8388,
13
+ )
14
+
15
+ assert config.label is None
16
+ assert config.extra == {}
17
+
18
+
19
+ def test_to_dict():
20
+ config = ShadowsocksConfig(
21
+ encryption="aes-256-gcm",
22
+ password="password",
23
+ address="example.com",
24
+ port=8388,
25
+ label="test",
26
+ extra={"plugin": "v2ray-plugin"},
27
+ )
28
+
29
+ assert config.to_dict() == {
30
+ "protocol": "shadowsocks",
31
+ "encryption": "aes-256-gcm",
32
+ "password": "password",
33
+ "address": "example.com",
34
+ "port": 8388,
35
+ "label": "test",
36
+ "extra": {"plugin": "v2ray-plugin"},
37
+ }
38
+
39
+
40
+ def test_extra():
41
+ config = ShadowsocksConfig(
42
+ encryption="aes-256-gcm",
43
+ password="password",
44
+ address="example.com",
45
+ port=8388,
46
+ extra={"plugin": "v2ray-plugin"},
47
+ )
48
+
49
+ data = config.to_dict()
50
+
51
+ assert data["extra"]["plugin"] == "v2ray-plugin"
52
+
53
+
54
+ def test_method_chaining():
55
+ config = ShadowsocksConfig(
56
+ encryption="aes-256-gcm",
57
+ password="password",
58
+ address="example.com",
59
+ port=8388,
60
+ )
61
+
62
+ config.update_encryption(
63
+ "chacha20-ietf-poly1305"
64
+ ).update_password(
65
+ "secret"
66
+ ).update_address(
67
+ "example.org"
68
+ ).update_port(
69
+ 443
70
+ )
71
+
72
+ assert config.encryption == "chacha20-ietf-poly1305"
73
+ assert config.password == "secret"
74
+ assert config.address == "example.org"
75
+ assert config.port == 443
76
+
77
+
78
+ @pytest.mark.parametrize(
79
+ "kwargs",
80
+ [
81
+ {"encryption": ""},
82
+ {"password": ""},
83
+ {"address": ""},
84
+ {"port": 0},
85
+ {"port": 1.2},
86
+ {"extra": 1},
87
+ ],
88
+ )
89
+ def test_invalid_values(kwargs):
90
+ params = {
91
+ "encryption": "aes-256-gcm",
92
+ "password": "password",
93
+ "address": "example.com",
94
+ "port": 8388,
95
+ }
96
+ params.update(kwargs)
97
+
98
+ with pytest.raises(ValueError):
99
+ ShadowsocksConfig(**params)
100
+
101
+
102
+ def test_to_uri_roundtrip():
103
+ config = ShadowsocksConfig(
104
+ encryption="aes-256-gcm",
105
+ password="password",
106
+ address="example.com",
107
+ port=8388,
108
+ label="test",
109
+ )
110
+
111
+ parsed = parse(config.to_uri())
112
+
113
+ assert parsed == config
114
+
115
+
116
+ def test_equality():
117
+ config1 = ShadowsocksConfig(
118
+ encryption="aes-256-gcm",
119
+ password="password",
120
+ address="example.com",
121
+ port=8388,
122
+ )
123
+
124
+ config2 = ShadowsocksConfig(
125
+ encryption="aes-256-gcm",
126
+ password="password",
127
+ address="example.com",
128
+ port=8388,
129
+ )
130
+
131
+ config3 = ShadowsocksConfig(
132
+ encryption="aes-256-gcm",
133
+ password="password",
134
+ address="example.org",
135
+ port=8388,
136
+ )
137
+
138
+ assert config1 == config2
139
+ assert config1 != config3
140
+ assert config1 != "config1"
141
+
142
+
143
+ def test_repr():
144
+ config = ShadowsocksConfig(
145
+ encryption="aes-256-gcm",
146
+ password="password",
147
+ address="example.com",
148
+ port=8388,
149
+ )
150
+
151
+ assert repr(config) == (
152
+ "ShadowsocksConfig(protocol=<Protocol.SHADOWSOCKS: "
153
+ "'ss'>, label=None)"
154
+ )
155
+
156
+
157
+ def test_update_extra():
158
+ config = ShadowsocksConfig(
159
+ encryption="aes-256-gcm",
160
+ password="password",
161
+ address="example.com",
162
+ port=8388,
163
+ )
164
+
165
+ config.update_extra(
166
+ {"plugin": "v2ray-plugin"}
167
+ )
168
+
169
+ assert config.extra["plugin"] == "v2ray-plugin"
170
+
171
+
172
+ def test_update_methods():
173
+ config = ShadowsocksConfig(
174
+ encryption="aes-256-gcm",
175
+ password="password",
176
+ address="example.com",
177
+ port=8388,
178
+ )
179
+
180
+ config.update_encryption(
181
+ "chacha20-ietf-poly1305"
182
+ )
183
+ config.update_password(
184
+ "secret"
185
+ )
186
+ config.update_address(
187
+ "example.org"
188
+ )
189
+ config.update_port(
190
+ 443
191
+ )
192
+
193
+ assert config.encryption == "chacha20-ietf-poly1305"
194
+ assert config.password == "secret"
195
+ assert config.address == "example.org"
196
+ assert config.port == 443