vyperling 0.0.1__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 (32) hide show
  1. vyperling-0.0.1/LICENSE +21 -0
  2. vyperling-0.0.1/PKG-INFO +491 -0
  3. vyperling-0.0.1/README.md +467 -0
  4. vyperling-0.0.1/pyproject.toml +55 -0
  5. vyperling-0.0.1/vyperling/__init__.py +3 -0
  6. vyperling-0.0.1/vyperling/c/UNITY_LICENSE +24 -0
  7. vyperling-0.0.1/vyperling/c/forge_mock.c +111 -0
  8. vyperling-0.0.1/vyperling/c/forge_mock.h +54 -0
  9. vyperling-0.0.1/vyperling/c/unity.c +2501 -0
  10. vyperling-0.0.1/vyperling/c/unity.h +698 -0
  11. vyperling-0.0.1/vyperling/c/unity_fixture.h +94 -0
  12. vyperling-0.0.1/vyperling/c/unity_internals.h +1183 -0
  13. vyperling-0.0.1/vyperling/cli.py +297 -0
  14. vyperling-0.0.1/vyperling/compiler.py +162 -0
  15. vyperling-0.0.1/vyperling/config.py +101 -0
  16. vyperling-0.0.1/vyperling/coverage.py +86 -0
  17. vyperling-0.0.1/vyperling/discoverer.py +77 -0
  18. vyperling-0.0.1/vyperling/errors.py +36 -0
  19. vyperling-0.0.1/vyperling/mockgen.py +403 -0
  20. vyperling-0.0.1/vyperling/reporter.py +138 -0
  21. vyperling-0.0.1/vyperling/runner.py +132 -0
  22. vyperling-0.0.1/vyperling/scaffold.py +67 -0
  23. vyperling-0.0.1/vyperling/templates/__init__.py +0 -0
  24. vyperling-0.0.1/vyperling/templates/mock_header.h.j2 +38 -0
  25. vyperling-0.0.1/vyperling/templates/mock_source.c.j2 +159 -0
  26. vyperling-0.0.1/vyperling/templates/scaffold_example_c.j2 +7 -0
  27. vyperling-0.0.1/vyperling/templates/scaffold_example_h.j2 +7 -0
  28. vyperling-0.0.1/vyperling/templates/scaffold_forge_yml.j2 +25 -0
  29. vyperling-0.0.1/vyperling/templates/scaffold_readme_md.j2 +29 -0
  30. vyperling-0.0.1/vyperling/templates/scaffold_test_example_c.j2 +18 -0
  31. vyperling-0.0.1/vyperling/toolchains.py +143 -0
  32. vyperling-0.0.1/vyperling/unity.py +60 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ericson Joseph
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do 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,491 @@
1
+ Metadata-Version: 2.4
2
+ Name: vyperling
3
+ Version: 0.0.1
4
+ Summary: Embedded C test runner with cross-compilation support
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Author: Ericson Joseph
8
+ Author-email: ericsonjoseph@gmail.com
9
+ Requires-Python: >=3.11,<4.0
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Requires-Dist: click (>=8.0,<9.0)
16
+ Requires-Dist: gcovr (>=7.0,<9.0)
17
+ Requires-Dist: jinja2 (>=3.0,<4.0)
18
+ Requires-Dist: pycparser (>=2.21)
19
+ Requires-Dist: pycparser-fake-libc (>=2.21)
20
+ Requires-Dist: pyyaml (>=6.0,<7.0)
21
+ Requires-Dist: rich (>=13.0,<15.0)
22
+ Description-Content-Type: text/markdown
23
+
24
+ # vyperling
25
+
26
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
27
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
28
+ [![PyPI version](https://img.shields.io/badge/PyPI-0.0.1-brightgreen.svg)](https://pypi.org/)
29
+ [![Build Status](https://img.shields.io/badge/status-active-brightgreen.svg)](https://github.com/ericsonjoseph/vyperling)
30
+
31
+ **Embedded C unit test runner with cross-compilation support.**
32
+ A pip-installable replacement for [Ceedling](https://github.com/ThrowTheSwitch/Ceedling) — no Ruby dependencies, modern Python-first design.
33
+
34
+ ## Overview
35
+
36
+ `vyperling` (`vpl` for short) is a complete embedded C testing framework that:
37
+
38
+ - 🔍 **Auto-discovers** `test_*.c` files in your test directory
39
+ - 🎯 **Generates CMock-style mocks** from C headers using pycparser + Jinja2
40
+ - 🔨 **Cross-compiles** for native (GCC) and embedded targets (ARM, MIPS, RISC-V, AVR) with parallel jobs
41
+ - 🖥️ **Executes** natively or under emulation (QEMU, simavr)
42
+ - 📊 **Parses** Unity test output with rich terminal reporting
43
+ - 📈 **Generates coverage** reports (gcov) for native targets
44
+ - 📋 **Exports** JUnit XML for CI/CD integration
45
+
46
+ Perfect for firmware development, embedded systems testing, and hardware validation workflows.
47
+
48
+ ## Quick Start
49
+
50
+ ### 1. Install
51
+
52
+ ```bash
53
+ pip install vyperling
54
+ # Alias 'vpl' is registered automatically
55
+ vpl --version
56
+ ```
57
+
58
+ Development (editable install from source):
59
+
60
+ ```bash
61
+ git clone https://github.com/ericsonjoseph/vyperling.git
62
+ cd vyperling
63
+ pip install -e .
64
+ ```
65
+
66
+ ### 2. Create a Project
67
+
68
+ ```bash
69
+ vpl new myproject
70
+ cd myproject
71
+ ```
72
+
73
+ This scaffolds:
74
+ - `forge.yml` — project configuration
75
+ - `src/` — source files under test
76
+ - `test/` — test files (test_*.c pattern)
77
+ - `mocks/` — auto-generated mocks
78
+
79
+ ### 3. Run Tests
80
+
81
+ ```bash
82
+ # Test native target (default)
83
+ vpl test
84
+
85
+ # Cross-compile for MIPS32
86
+ vpl test --target mips32
87
+
88
+ # Run specific tests (pattern match)
89
+ vpl test -k uart
90
+
91
+ # Parallel compilation (4 jobs)
92
+ vpl test -j4
93
+
94
+ # Generate coverage report (native only)
95
+ vpl test --coverage
96
+
97
+ # Export JUnit XML for CI
98
+ vpl test --output junit
99
+ ```
100
+
101
+ ## Commands Reference
102
+
103
+ All commands use **`vyperling`** or **`vpl`** interchangeably.
104
+
105
+ ### `vpl test` — Discover, Compile, Run, Report
106
+
107
+ ```bash
108
+ vpl test [OPTIONS]
109
+
110
+ OPTIONS:
111
+ --target TEXT Toolchain target (default: targets.default from forge.yml)
112
+ -k, --filter PATTERN Run only tests matching PATTERN
113
+ -j, --jobs N Parallel compile jobs (default: 1)
114
+ --coverage Enable gcov coverage (native target only)
115
+ --output FORMAT Export results: junit
116
+ -v, --verbose Print every compiler command
117
+ --no-mock Skip automatic mock generation
118
+ ```
119
+
120
+ **Example:** Test UART module with coverage on 4 parallel jobs:
121
+ ```bash
122
+ vpl test -k uart -j4 --coverage
123
+ ```
124
+
125
+ ### `vpl mock` — Generate Mocks from Headers
126
+
127
+ Generate CMock-style mocks from C header files:
128
+
129
+ ```bash
130
+ vpl mock src/uart.h src/spi.h
131
+
132
+ # Or mock all headers in configured source dirs
133
+ vpl mock --all
134
+
135
+ # Use a specific toolchain's preprocessor
136
+ vpl mock --target arm-cortex-m4 src/uart.h
137
+ ```
138
+
139
+ Output: `mocks/mock_uart.{c,h}` and `mocks/mock_spi.{c,h}`
140
+
141
+ ### `vpl build` — Compile Only (No Execution)
142
+
143
+ ```bash
144
+ vpl build [OPTIONS]
145
+
146
+ OPTIONS:
147
+ --target TEXT Toolchain target
148
+ -j, --jobs N Parallel compile jobs
149
+ -v, --verbose Print compiler commands
150
+ --no-mock Skip mock generation
151
+ ```
152
+
153
+ Useful for checking compilation without running tests:
154
+ ```bash
155
+ vpl build --target arm-cortex-m4 --verbose
156
+ ```
157
+
158
+ ### `vpl targets` — List Available Toolchains
159
+
160
+ ```bash
161
+ vpl targets
162
+ ```
163
+
164
+ Shows:
165
+ - **Built-in targets** (native, mips32, mips32el, arm-cortex-m4, riscv32, avr)
166
+ - **Project-defined targets** (from `forge.yml`)
167
+
168
+ ### `vpl clean` — Remove Build Artifacts
169
+
170
+ ```bash
171
+ vpl clean # Remove all build directories
172
+ vpl clean --target mips32 # Remove only target's build dir
173
+ ```
174
+
175
+ ### `vpl --version` / `vpl --help`
176
+
177
+ Show version or full command help.
178
+
179
+ ## Cross-Compilation Targets
180
+
181
+ | Target | Triplet | Emulator | Install (Debian/Ubuntu) |
182
+ |--------|---------|----------|------------------------|
183
+ | `native` | (native) | direct exec | (included with GCC) |
184
+ | `mips32` | `mips-linux-gnu` | QEMU | `gcc-mips-linux-gnu qemu-user` |
185
+ | `mips32el` | `mipsel-linux-gnu` | QEMU | `gcc-mipsel-linux-gnu qemu-user` |
186
+ | `arm-cortex-m4` | `arm-none-eabi` | QEMU | `gcc-arm-none-eabi qemu-user` |
187
+ | `riscv32` | `riscv64-unknown-elf` | QEMU | `gcc-riscv64-unknown-elf qemu-user` |
188
+ | `avr` | `avr` | simavr | `gcc-avr avr-libc simavr` |
189
+
190
+ **Installation on Ubuntu/Debian:**
191
+
192
+ ```bash
193
+ # Native (GCC)
194
+ sudo apt install gcc build-essential
195
+
196
+ # MIPS cross-compile
197
+ sudo apt install gcc-mips-linux-gnu qemu-user
198
+
199
+ # ARM Cortex-M4 (bare-metal)
200
+ sudo apt install gcc-arm-none-eabi qemu-user
201
+
202
+ # RISC-V
203
+ sudo apt install gcc-riscv64-unknown-elf qemu-user
204
+
205
+ # AVR (Arduino)
206
+ sudo apt install gcc-avr avr-libc simavr
207
+ ```
208
+
209
+ ### Custom Toolchains
210
+
211
+ Define custom targets in `forge.yml`:
212
+
213
+ ```yaml
214
+ project:
215
+ name: myproject
216
+
217
+ toolchains:
218
+ custom-arm:
219
+ description: "Custom ARM GCC 12.2"
220
+ cc: "arm-linux-gcc-12.2"
221
+ ar: "arm-linux-ar-12.2"
222
+ cflags: ["-mcpu=cortex-a7", "-mfloat-abi=hard"]
223
+ emulator: qemu-arm-static
224
+ sysroot: /path/to/sysroot
225
+
226
+ targets:
227
+ default: native
228
+ ```
229
+
230
+ ## Configuration (`forge.yml`)
231
+
232
+ Minimal required:
233
+
234
+ ```yaml
235
+ project:
236
+ name: MyProject
237
+ ```
238
+
239
+ Full example with all options:
240
+
241
+ ```yaml
242
+ project:
243
+ name: my-firmware
244
+ src_dirs:
245
+ - src
246
+ - lib/hal
247
+ test_dir: test
248
+ include_dirs:
249
+ - src
250
+ - lib/hal/include
251
+ build_dir: build
252
+ mock_dir: mocks
253
+
254
+ targets:
255
+ default: native
256
+
257
+ compiler:
258
+ extra_cflags:
259
+ - -Wall
260
+ - -Wextra
261
+ - -pedantic
262
+ defines:
263
+ - DEBUG=1
264
+ - VERSION=1.0.0
265
+
266
+ toolchains:
267
+ custom-mcu:
268
+ description: "STM32 Cross-Compile"
269
+ cc: arm-none-eabi-gcc
270
+ ar: arm-none-eabi-ar
271
+ cflags:
272
+ - -mcpu=cortex-m4
273
+ - -mthumb
274
+ emulator: qemu-arm-static
275
+ ```
276
+
277
+ ## Project Layout
278
+
279
+ After `vpl new myproject`:
280
+
281
+ ```
282
+ myproject/
283
+ ├── forge.yml # Project configuration
284
+ ├── src/ # Source files under test
285
+ │ ├── uart.h
286
+ │ ├── uart.c
287
+ │ └── spi.c
288
+ ├── test/ # Unit tests
289
+ │ ├── test_uart.c
290
+ │ └── test_spi.c
291
+ └── mocks/ # Auto-generated mocks (created by 'vpl mock')
292
+ ├── mock_uart.h
293
+ ├── mock_uart.c
294
+ ├── mock_spi.h
295
+ └── mock_spi.c
296
+ ```
297
+
298
+ ### Test File Pattern
299
+
300
+ Tests use the **`test_*.c`** pattern. Each test file:
301
+ - Includes `unity.h` (provided by vyperling)
302
+ - Includes mocks via `#include "mock_<dependency>.h"`
303
+ - Defines test cases with `void test_<name>(void)`
304
+
305
+ **Example: `test/test_uart.c`**
306
+
307
+ ```c
308
+ #include "unity.h"
309
+ #include "uart.h"
310
+ #include "mock_gpio.h"
311
+
312
+ void setUp(void) {
313
+ // Called before each test
314
+ }
315
+
316
+ void tearDown(void) {
317
+ // Called after each test
318
+ }
319
+
320
+ void test_uart_init_should_configure_pins(void) {
321
+ gpio_init_Expect();
322
+ uart_init();
323
+ TEST_ASSERT_TRUE(1);
324
+ }
325
+
326
+ void test_uart_send_should_transmit_byte(void) {
327
+ uart_send(0x42);
328
+ TEST_ASSERT_EQUAL_INT(0x42, last_byte_sent);
329
+ }
330
+ ```
331
+
332
+ ## Test Framework
333
+
334
+ vyperling uses:
335
+
336
+ - **Unity** — lightweight C assertion framework ([ThrowTheSwitch](https://github.com/ThrowTheSwitch/Unity))
337
+ - **CMock** — automated mocking for C functions (auto-generated via `vpl mock`)
338
+ - **pycparser** — C header parser for mock generation
339
+
340
+ ### Assertion Macros
341
+
342
+ Unity provides rich assertions:
343
+
344
+ ```c
345
+ // Basic checks
346
+ TEST_ASSERT_TRUE(condition)
347
+ TEST_ASSERT_FALSE(condition)
348
+ TEST_ASSERT_NULL(ptr)
349
+ TEST_ASSERT_NOT_NULL(ptr)
350
+
351
+ // Equality
352
+ TEST_ASSERT_EQUAL_INT(expected, actual)
353
+ TEST_ASSERT_EQUAL_UINT(expected, actual)
354
+ TEST_ASSERT_EQUAL_HEX(expected, actual)
355
+ TEST_ASSERT_EQUAL_STRING(expected, actual)
356
+
357
+ // Arrays
358
+ TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, len)
359
+ TEST_ASSERT_EQUAL_MEMORY(expected, actual, len)
360
+
361
+ // Floating point
362
+ TEST_ASSERT_EQUAL_FLOAT(expected, actual, delta)
363
+ ```
364
+
365
+ See [Unity documentation](https://github.com/ThrowTheSwitch/Unity/blob/master/docs/UnityAssertionsReference.md) for complete reference.
366
+
367
+ ## Architecture
368
+
369
+ vyperling's pipeline flows through 8 independent modules, connected by dataclasses:
370
+
371
+ ```
372
+ TestUnit ──→ CompileResult ──→ RunResult
373
+ ```
374
+
375
+ | Module | Responsibility |
376
+ |--------|---|
377
+ | **config.py** | Load `forge.yml`, resolve paths, manage project settings |
378
+ | **toolchains.py** | Maintain toolchain registry (builtin + user-defined) |
379
+ | **discoverer.py** | Glob `test_*.c`, match source files, emit `TestUnit` list |
380
+ | **mockgen.py** | Parse headers with pycparser, generate mocks via Jinja2 |
381
+ | **compiler.py** | Invoke GCC with ThreadPoolExecutor, cache via `.forge_deps.json` |
382
+ | **runner.py** | Execute binaries natively or under QEMU/simavr, parse Unity output |
383
+ | **reporter.py** | Rich terminal tables + JUnit XML export |
384
+ | **coverage.py** | Generate gcov reports (native-only, best-effort) |
385
+
386
+ **Key invariant:** Each module emits structured output (dataclass) that the next consumes — no hidden state.
387
+
388
+ ## Development
389
+
390
+ ### Install for Development
391
+
392
+ ```bash
393
+ git clone https://github.com/ericsonjoseph/vyperling.git
394
+ cd vyperling
395
+ pip install -e .
396
+ ```
397
+
398
+ ### Run Tests
399
+
400
+ ```bash
401
+ # Full test suite (coverage on by default)
402
+ pytest
403
+
404
+ # Single test file
405
+ pytest tests/test_mockgen.py
406
+
407
+ # Single test by name
408
+ pytest -k test_cross_compile
409
+
410
+ # Disable coverage
411
+ pytest --no-cov
412
+ ```
413
+
414
+ ### Project Structure
415
+
416
+ - `vyperling/` — main library
417
+ - `cli.py` — Click entry point (commands: test, build, mock, clean, targets, new)
418
+ - `config.py` — forge.yml loader and config validation
419
+ - `toolchains.py` — Toolchain dataclass + registry
420
+ - `discoverer.py` — test file discovery
421
+ - `mockgen.py` — C header parsing + mock generation
422
+ - `compiler.py` — GCC invocation with caching and parallel jobs
423
+ - `runner.py` — test execution and Unity output parsing
424
+ - `reporter.py` — rich terminal output + JUnit export
425
+ - `coverage.py` — gcov/gcovr pipeline
426
+ - `scaffold.py` — project template generation
427
+ - `errors.py` — exception hierarchy
428
+ - `unity.py` — Unity C framework accessor
429
+ - `c/` — vendored C assets (Unity v2.6.1 + forge_mock)
430
+ - `templates/` — Jinja2 templates for mocks and scaffolding
431
+ - `tests/` — comprehensive Python test suite
432
+ - `DEVELOPMENT_PLAN.md` — implementation checklist (all 17 steps ✅)
433
+
434
+ ## Dependencies
435
+
436
+ **Runtime:**
437
+ - `click>=8.0` — CLI framework
438
+ - `rich>=13.0` — terminal formatting
439
+ - `pyyaml>=6.0` — YAML config parsing
440
+ - `pycparser>=2.21` — C header parsing
441
+ - `jinja2>=3.0` — template engine
442
+ - `gcovr>=7.0` — coverage reporting
443
+
444
+ **Development:**
445
+ - `pytest>=7.0` — testing
446
+ - `pytest-cov>=4.0` — coverage measurement
447
+
448
+ ## Known Limitations (v0.0.1)
449
+
450
+ - **Mock generation**: Skips variadic functions, function-pointer params, and incomplete struct-by-value params (warns during generation)
451
+ - **Coverage**: Native target only; requires GCC with `-fprofile-arcs -ftest-coverage` support
452
+ - **Emulation**: Timeout-based (default 30s per test binary)
453
+
454
+ ## Roadmap
455
+
456
+ | Phase | Items |
457
+ |-------|-------|
458
+ | v0.1 | ✅ Core pipeline (discover → mock → compile → run → report) |
459
+ | v0.2 | 📋 Enhanced mock generation (variadic support, callbacks) |
460
+ | v0.3 | 📋 CI/CD integration templates (GitHub Actions, GitLab CI) |
461
+ | v0.4 | 📋 IDE integration (VS Code extension) |
462
+
463
+ ## Contributing
464
+
465
+ Contributions welcome! Please:
466
+
467
+ 1. Fork the repository
468
+ 2. Create a feature branch (`git checkout -b feature/my-feature`)
469
+ 3. Write tests for your changes
470
+ 4. Run the full test suite (`pytest`)
471
+ 5. Commit with conventional messages
472
+ 6. Push and open a pull request
473
+
474
+ For major changes, please open an issue first to discuss.
475
+
476
+ ## License
477
+
478
+ MIT — see [LICENSE](LICENSE) file for details.
479
+
480
+ ## Credits
481
+
482
+ - **vyperling** by [Ericson Joseph](https://github.com/ericsonjoseph)
483
+ - **Unity** testing framework by [ThrowTheSwitch](https://github.com/ThrowTheSwitch/Unity)
484
+ - **CMock** concepts adapted from [CMock](https://github.com/ThrowTheSwitch/CMock)
485
+
486
+ ## Support
487
+
488
+ - 📖 [Architecture Documentation](vyperling-architecture.md)
489
+ - 🐛 [Issue Tracker](https://github.com/ericsonjoseph/vyperling/issues)
490
+ - 💬 [Discussions](https://github.com/ericsonjoseph/vyperling/discussions)
491
+