bean-test 0.1.0__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) `2026` `numen-0`
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,282 @@
1
+ Metadata-Version: 2.4
2
+ Name: bean-test
3
+ Version: 0.1.0
4
+ Summary: Tiny test framework
5
+ Author-email: numen-0 <numen.0x1dea@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) `2026` `numen-0`
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
11
+ this software and associated documentation files (the "Software"), to deal in
12
+ the Software without restriction, including without limitation the rights to
13
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
14
+ of the Software, and to permit persons to whom the Software is furnished to do
15
+ so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: homepage, https://github.com/numen-0/bean
29
+ Project-URL: repository, https://github.com/numen-0/bean
30
+ Project-URL: issues, https://github.com/numen-0/bean/issues
31
+ Project-URL: documentation, https://github.com/numen-0/bean/bean-http/src/bean/test.py
32
+ Keywords: bean,bean.test
33
+ Classifier: Development Status :: 2 - Pre-Alpha
34
+ Classifier: Environment :: Console
35
+ Classifier: Intended Audience :: Developers
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Programming Language :: Python
39
+ Classifier: Programming Language :: Python :: 3
40
+ Classifier: Programming Language :: Python :: 3 :: Only
41
+ Classifier: Programming Language :: Python :: 3.14
42
+ Classifier: Programming Language :: Python :: 3.15
43
+ Classifier: Topic :: Scientific/Engineering
44
+ Classifier: Topic :: Software Development
45
+ Classifier: Topic :: Software Development :: Libraries
46
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
47
+ Classifier: Typing :: Typed
48
+ Requires-Python: >=3.14
49
+ Description-Content-Type: text/markdown
50
+ License-File: LICENSE
51
+ Dynamic: license-file
52
+
53
+ # bean.test
54
+
55
+ `bean.test` is a tiny test framework.
56
+
57
+ > Just enough to pick apart rotten beans.
58
+
59
+ ---
60
+
61
+ ## Overview
62
+
63
+ With `bean.test` you get:
64
+
65
+ - A small, fluent assertion API.
66
+ - Test data generation helpers.
67
+ - Simple test registration and reporting.
68
+ - test discovery
69
+
70
+ ```py
71
+ from bean import test
72
+
73
+ @test.register()
74
+ def test_something():
75
+ test.expect(1 + 1).Equal(2)
76
+ ```
77
+
78
+ > **Note**:
79
+ >
80
+ > To quickly inspect the public API:
81
+ >
82
+ > ```sh
83
+ > python -c "
84
+ > import bean.test as bean
85
+ > for v in sorted(dir(bean)):
86
+ > print(f'- {v}')
87
+ > "
88
+ > ```
89
+
90
+ ## Installation
91
+
92
+ Using `pip`:
93
+
94
+ ```sh
95
+ pip install --upgrade bean-test
96
+ ```
97
+
98
+ Using `curl` (direct download):
99
+
100
+ ```sh
101
+ curl -Ls \
102
+ https://raw.githubusercontent.com/numen-0/bean/main/bean-test/src/bean/test.py
103
+ ```
104
+
105
+ ## Command Line
106
+
107
+ `bean.test` can be used directly as a test runner.
108
+
109
+ ```sh
110
+ python -m bean.test tests/
111
+ ```
112
+
113
+ By default, files matching `*.py` are discovered. Use `--pattern` to change the
114
+ pattern:
115
+
116
+ ```sh
117
+ python -m bean.test tests/ --pattern "test_*.py"
118
+ ```
119
+
120
+ Run only specific namespaces:
121
+
122
+ ```sh
123
+ python -m bean.test tests/ -n unit integration
124
+ ```
125
+
126
+ > **Note**:
127
+ >
128
+ > For more information, run:
129
+ >
130
+ > ```sh
131
+ > python -m bean.test --help
132
+ > ```
133
+
134
+ ## API
135
+
136
+ This is a quick reference for the main `API`.
137
+
138
+ For full details, see the [source code](/bean-test/src/bean/test.py).
139
+
140
+ ### Test Registration
141
+
142
+ Tests can be registered under different namespaces.
143
+
144
+ ```py
145
+ @register("math")
146
+ def test_addition(): ...
147
+
148
+ @register("http")
149
+ def test_request(): ...
150
+ ```
151
+
152
+ ### Data Generation
153
+
154
+ `rand` provides small helpers for generating and composing random test data.
155
+
156
+ ```py
157
+ from bean.test import rand
158
+
159
+ list(rand.cases( # generator for tuple[bool, tuple[str, int]]
160
+ rand(bool), # <- retrieve bool
161
+ rand.choice(*rand.product( # <- chose a tuple[str, int]
162
+ ("a", "b", "c"),
163
+ (1, 2, 3),
164
+ )),
165
+ count=5,
166
+ seed=42,
167
+ ))
168
+ ```
169
+
170
+ ### The Lab
171
+
172
+ `Lab` is the singleton responsible for running tests and generating reports
173
+
174
+ | member | descrition |
175
+ |:-------------------------:|:-------------------------------------------------|
176
+ | `report(ns)` | Generate report for all or the given namespaces |
177
+ | `print(ns)` | Generate a report and write it to stdout |
178
+
179
+ ### Expect Assertions
180
+
181
+ Fluent assertions for inspecting values.
182
+
183
+ | **Method** | **Descrition** |
184
+ |:--------------------------|:-------------------------------------------------|
185
+ | *misc* | - |
186
+ | `Set(value)` | Replace asserted value |
187
+ | `Map(fn)` | Transform asserted value |
188
+ | `MapEach(fn)` | Transform asserted value items |
189
+ | `Check(predicate)` | Assert value satisfies predicate |
190
+ | *context* | - |
191
+ | `Raises(exception)` | Context manager asserting that an exception is raised |
192
+ | *turthiness* | - |
193
+ | `Truthy()` | Assert value is truthy |
194
+ | `Falsy()` | Assert value is falsy |
195
+ | `Empty()` | Assert value has length zero |
196
+ | `NotEmpty()` | Assert value has non-zero length |
197
+ | *equality* | - |
198
+ | `Equal(expected)` | Assert value == expected |
199
+ | `NotEqual(expected)` | Assert value != expected |
200
+ | `Greater(expected)` | Assert value < expected |
201
+ | `GreaterEqual(expected)` | Assert value <= expected |
202
+ | `Less(expected)` | Assert value > expected |
203
+ | `LessEqual(expected)` | Assert value >= expected |
204
+ | `AlmostEqual(expected)` | Assert numeric values are approximately equal |
205
+ | `NotAlmostEqual(expected)` | Assert numeric values are not approximately equal |
206
+ | *type* identity | - |
207
+ | `Is(expected)` | Assert value is expected |
208
+ | `IsNot(expected)` | Assert value is not expected |
209
+ | `IsNone()` | Assert value is `None` |
210
+ | `IsNotNone()` | Assert value is not `None` |
211
+ | `IsInstance(cls)` | Assert value is an instance of a type |
212
+ | `IsNotInstance(cls)` | Assert value is not an instance of a type |
213
+ | `IsNumeric()` | Assert value is numeric |
214
+ | `IsString()` | Assert value is a string |
215
+ | `IsEnum()` | Assert value is a enum |
216
+ | `IsIterable()` | Assert value is iterable |
217
+ | *strings* | - |
218
+ | `StartsWith(expected)` | Assert value starts with given prefix |
219
+ | `NotStartsWith(expected)` | Assert value doesn't start with given prefix |
220
+ | `EndsWith(expected)` | Assert value ends with given suffix |
221
+ | `NotEndsWith(expected)` | Assert value doesn't end with given suffix |
222
+ | `Regex(expected)` | Assert value matches regular expression |
223
+ | `NotRegex(expected)` | Assert value doesn't matche regular expression |
224
+ | *quantifiers* | - |
225
+ | `All(predicate)` | Assert every item satisfies predicate |
226
+ | `Any(predicate)` | Assert at least one item satisfies predicate |
227
+ | `NotAny(predicate)` | Assert no item satisfies predicate |
228
+ | `IsSorted()` | Assert value is sorted |
229
+ | *quantifiers* | - |
230
+ | `In(expected)` | Assert value is contained in expected |
231
+ | `NotIn(expected)` | Assert value isn't contained in expected |
232
+ | `HasAttr(expected)` | Assert value has an attribute |
233
+ | `NotHasAttr(expected)` | Assert value hasn't an attribute |
234
+ | *collections* | - |
235
+ | `SequenceEqual(expected)` | Assert equal items in the same order |
236
+ | `ContainerEqual(expected)` | Assert equal items, ignoring order and preserving multiplicity |
237
+ | `SetEqual(expected)` | Assert equal items using set semantics |
238
+ | `NotSetEqual(expected)` | Assert containers are not set-equal |
239
+ | `Subset(expected)` | Assert every item is contained in expected |
240
+ | `NotSubset(expected)` | Assert at least one item is outside expected |
241
+ | `Superset(expected)` | Assert value contains every expected item |
242
+ | `NotSuperset(expected)` | Assert at least one expected item is missing |
243
+ | `Intersects(expected)` | Assert containers have no items in common |
244
+ | `Disjoint(expected)` | Assert containers have at least one item in common |
245
+
246
+ > **Note**: Every method returns `self`, so multiple assertions can be chained
247
+
248
+ ## Example
249
+
250
+ ```py
251
+ from bean import test
252
+
253
+ @test.register()
254
+ def test_addition():
255
+ test.expect(1 + 1).Equal(2)
256
+
257
+ @test.register()
258
+ def test_string():
259
+ test.expect("hello world") \
260
+ .IsString() \
261
+ .NotEmpty() \
262
+ .StartsWith("hello") \
263
+ .EndsWith("world")
264
+
265
+ @test.register()
266
+ def test_collections():
267
+ test.expect([1, 2, 3]).SequenceEqual([1, 2, 3])
268
+ test.expect([3, 1, 2]).SetEqual([1, 2, 3])
269
+ test.expect([1, 2]).Subset([1, 2, 3])
270
+
271
+ @test.register()
272
+ def test_exception():
273
+ with test.expect.Raises(ValueError):
274
+ int("bean")
275
+
276
+ test.Lab.print()
277
+ ```
278
+
279
+ ## License
280
+
281
+ All the repo falls under the [MIT License](/LICENSE).
282
+
@@ -0,0 +1,230 @@
1
+ # bean.test
2
+
3
+ `bean.test` is a tiny test framework.
4
+
5
+ > Just enough to pick apart rotten beans.
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ With `bean.test` you get:
12
+
13
+ - A small, fluent assertion API.
14
+ - Test data generation helpers.
15
+ - Simple test registration and reporting.
16
+ - test discovery
17
+
18
+ ```py
19
+ from bean import test
20
+
21
+ @test.register()
22
+ def test_something():
23
+ test.expect(1 + 1).Equal(2)
24
+ ```
25
+
26
+ > **Note**:
27
+ >
28
+ > To quickly inspect the public API:
29
+ >
30
+ > ```sh
31
+ > python -c "
32
+ > import bean.test as bean
33
+ > for v in sorted(dir(bean)):
34
+ > print(f'- {v}')
35
+ > "
36
+ > ```
37
+
38
+ ## Installation
39
+
40
+ Using `pip`:
41
+
42
+ ```sh
43
+ pip install --upgrade bean-test
44
+ ```
45
+
46
+ Using `curl` (direct download):
47
+
48
+ ```sh
49
+ curl -Ls \
50
+ https://raw.githubusercontent.com/numen-0/bean/main/bean-test/src/bean/test.py
51
+ ```
52
+
53
+ ## Command Line
54
+
55
+ `bean.test` can be used directly as a test runner.
56
+
57
+ ```sh
58
+ python -m bean.test tests/
59
+ ```
60
+
61
+ By default, files matching `*.py` are discovered. Use `--pattern` to change the
62
+ pattern:
63
+
64
+ ```sh
65
+ python -m bean.test tests/ --pattern "test_*.py"
66
+ ```
67
+
68
+ Run only specific namespaces:
69
+
70
+ ```sh
71
+ python -m bean.test tests/ -n unit integration
72
+ ```
73
+
74
+ > **Note**:
75
+ >
76
+ > For more information, run:
77
+ >
78
+ > ```sh
79
+ > python -m bean.test --help
80
+ > ```
81
+
82
+ ## API
83
+
84
+ This is a quick reference for the main `API`.
85
+
86
+ For full details, see the [source code](/bean-test/src/bean/test.py).
87
+
88
+ ### Test Registration
89
+
90
+ Tests can be registered under different namespaces.
91
+
92
+ ```py
93
+ @register("math")
94
+ def test_addition(): ...
95
+
96
+ @register("http")
97
+ def test_request(): ...
98
+ ```
99
+
100
+ ### Data Generation
101
+
102
+ `rand` provides small helpers for generating and composing random test data.
103
+
104
+ ```py
105
+ from bean.test import rand
106
+
107
+ list(rand.cases( # generator for tuple[bool, tuple[str, int]]
108
+ rand(bool), # <- retrieve bool
109
+ rand.choice(*rand.product( # <- chose a tuple[str, int]
110
+ ("a", "b", "c"),
111
+ (1, 2, 3),
112
+ )),
113
+ count=5,
114
+ seed=42,
115
+ ))
116
+ ```
117
+
118
+ ### The Lab
119
+
120
+ `Lab` is the singleton responsible for running tests and generating reports
121
+
122
+ | member | descrition |
123
+ |:-------------------------:|:-------------------------------------------------|
124
+ | `report(ns)` | Generate report for all or the given namespaces |
125
+ | `print(ns)` | Generate a report and write it to stdout |
126
+
127
+ ### Expect Assertions
128
+
129
+ Fluent assertions for inspecting values.
130
+
131
+ | **Method** | **Descrition** |
132
+ |:--------------------------|:-------------------------------------------------|
133
+ | *misc* | - |
134
+ | `Set(value)` | Replace asserted value |
135
+ | `Map(fn)` | Transform asserted value |
136
+ | `MapEach(fn)` | Transform asserted value items |
137
+ | `Check(predicate)` | Assert value satisfies predicate |
138
+ | *context* | - |
139
+ | `Raises(exception)` | Context manager asserting that an exception is raised |
140
+ | *turthiness* | - |
141
+ | `Truthy()` | Assert value is truthy |
142
+ | `Falsy()` | Assert value is falsy |
143
+ | `Empty()` | Assert value has length zero |
144
+ | `NotEmpty()` | Assert value has non-zero length |
145
+ | *equality* | - |
146
+ | `Equal(expected)` | Assert value == expected |
147
+ | `NotEqual(expected)` | Assert value != expected |
148
+ | `Greater(expected)` | Assert value < expected |
149
+ | `GreaterEqual(expected)` | Assert value <= expected |
150
+ | `Less(expected)` | Assert value > expected |
151
+ | `LessEqual(expected)` | Assert value >= expected |
152
+ | `AlmostEqual(expected)` | Assert numeric values are approximately equal |
153
+ | `NotAlmostEqual(expected)` | Assert numeric values are not approximately equal |
154
+ | *type* identity | - |
155
+ | `Is(expected)` | Assert value is expected |
156
+ | `IsNot(expected)` | Assert value is not expected |
157
+ | `IsNone()` | Assert value is `None` |
158
+ | `IsNotNone()` | Assert value is not `None` |
159
+ | `IsInstance(cls)` | Assert value is an instance of a type |
160
+ | `IsNotInstance(cls)` | Assert value is not an instance of a type |
161
+ | `IsNumeric()` | Assert value is numeric |
162
+ | `IsString()` | Assert value is a string |
163
+ | `IsEnum()` | Assert value is a enum |
164
+ | `IsIterable()` | Assert value is iterable |
165
+ | *strings* | - |
166
+ | `StartsWith(expected)` | Assert value starts with given prefix |
167
+ | `NotStartsWith(expected)` | Assert value doesn't start with given prefix |
168
+ | `EndsWith(expected)` | Assert value ends with given suffix |
169
+ | `NotEndsWith(expected)` | Assert value doesn't end with given suffix |
170
+ | `Regex(expected)` | Assert value matches regular expression |
171
+ | `NotRegex(expected)` | Assert value doesn't matche regular expression |
172
+ | *quantifiers* | - |
173
+ | `All(predicate)` | Assert every item satisfies predicate |
174
+ | `Any(predicate)` | Assert at least one item satisfies predicate |
175
+ | `NotAny(predicate)` | Assert no item satisfies predicate |
176
+ | `IsSorted()` | Assert value is sorted |
177
+ | *quantifiers* | - |
178
+ | `In(expected)` | Assert value is contained in expected |
179
+ | `NotIn(expected)` | Assert value isn't contained in expected |
180
+ | `HasAttr(expected)` | Assert value has an attribute |
181
+ | `NotHasAttr(expected)` | Assert value hasn't an attribute |
182
+ | *collections* | - |
183
+ | `SequenceEqual(expected)` | Assert equal items in the same order |
184
+ | `ContainerEqual(expected)` | Assert equal items, ignoring order and preserving multiplicity |
185
+ | `SetEqual(expected)` | Assert equal items using set semantics |
186
+ | `NotSetEqual(expected)` | Assert containers are not set-equal |
187
+ | `Subset(expected)` | Assert every item is contained in expected |
188
+ | `NotSubset(expected)` | Assert at least one item is outside expected |
189
+ | `Superset(expected)` | Assert value contains every expected item |
190
+ | `NotSuperset(expected)` | Assert at least one expected item is missing |
191
+ | `Intersects(expected)` | Assert containers have no items in common |
192
+ | `Disjoint(expected)` | Assert containers have at least one item in common |
193
+
194
+ > **Note**: Every method returns `self`, so multiple assertions can be chained
195
+
196
+ ## Example
197
+
198
+ ```py
199
+ from bean import test
200
+
201
+ @test.register()
202
+ def test_addition():
203
+ test.expect(1 + 1).Equal(2)
204
+
205
+ @test.register()
206
+ def test_string():
207
+ test.expect("hello world") \
208
+ .IsString() \
209
+ .NotEmpty() \
210
+ .StartsWith("hello") \
211
+ .EndsWith("world")
212
+
213
+ @test.register()
214
+ def test_collections():
215
+ test.expect([1, 2, 3]).SequenceEqual([1, 2, 3])
216
+ test.expect([3, 1, 2]).SetEqual([1, 2, 3])
217
+ test.expect([1, 2]).Subset([1, 2, 3])
218
+
219
+ @test.register()
220
+ def test_exception():
221
+ with test.expect.Raises(ValueError):
222
+ int("bean")
223
+
224
+ test.Lab.print()
225
+ ```
226
+
227
+ ## License
228
+
229
+ All the repo falls under the [MIT License](/LICENSE).
230
+
@@ -0,0 +1,52 @@
1
+ [project]
2
+ name = "bean-test"
3
+ description = "Tiny test framework"
4
+ dynamic = ["version"]
5
+ dependencies = []
6
+ requires-python = ">=3.14"
7
+
8
+ authors = [
9
+ { name = "numen-0", email = "numen.0x1dea@gmail.com" },
10
+ ]
11
+ readme = "README.md"
12
+ license = { file = "LICENSE" }
13
+
14
+ keywords = [
15
+ "bean",
16
+ "bean.test",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 2 - Pre-Alpha",
20
+ "Environment :: Console",
21
+ "Intended Audience :: Developers",
22
+ "License :: OSI Approved :: MIT License",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3 :: Only",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Programming Language :: Python :: 3.15",
29
+ "Topic :: Scientific/Engineering",
30
+ "Topic :: Software Development",
31
+ "Topic :: Software Development :: Libraries",
32
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
33
+ "Typing :: Typed",
34
+ ]
35
+
36
+ [project.urls]
37
+ homepage = "https://github.com/numen-0/bean"
38
+ repository = "https://github.com/numen-0/bean"
39
+ issues = "https://github.com/numen-0/bean/issues"
40
+ documentation = "https://github.com/numen-0/bean/bean-http/src/bean/test.py"
41
+
42
+ [build-system]
43
+ requires = ["setuptools>=64", "wheel"]
44
+ build-backend = "setuptools.build_meta"
45
+
46
+ [tool.setuptools.dynamic]
47
+ version = { attr = "bean.test.__version__" }
48
+
49
+ [tool.setuptools.packages.find]
50
+ where = ["src"]
51
+ include = ["bean*"]
52
+ namespaces = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+