pytest-embedded-arduino-cli 0.2.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.
- pytest_embedded_arduino_cli-0.2.0/.github/workflows/release.yml +157 -0
- pytest_embedded_arduino_cli-0.2.0/.github/workflows/test.yml +29 -0
- pytest_embedded_arduino_cli-0.2.0/.gitignore +37 -0
- pytest_embedded_arduino_cli-0.2.0/.python-version +1 -0
- pytest_embedded_arduino_cli-0.2.0/CHANGELOG.md +7 -0
- pytest_embedded_arduino_cli-0.2.0/LICENSE +21 -0
- pytest_embedded_arduino_cli-0.2.0/PKG-INFO +229 -0
- pytest_embedded_arduino_cli-0.2.0/README.ja.md +217 -0
- pytest_embedded_arduino_cli-0.2.0/README.md +213 -0
- pytest_embedded_arduino_cli-0.2.0/SPEC.ja.md +507 -0
- pytest_embedded_arduino_cli-0.2.0/examples/basic/basic.ino +10 -0
- pytest_embedded_arduino_cli-0.2.0/examples/basic/sketch.yaml +13 -0
- pytest_embedded_arduino_cli-0.2.0/examples/basic/test_basic.py +2 -0
- pytest_embedded_arduino_cli-0.2.0/examples/pytest.ini +3 -0
- pytest_embedded_arduino_cli-0.2.0/examples/wifi/build_config.toml +3 -0
- pytest_embedded_arduino_cli-0.2.0/examples/wifi/sketch.yaml +17 -0
- pytest_embedded_arduino_cli-0.2.0/examples/wifi/test_wifi.py +19 -0
- pytest_embedded_arduino_cli-0.2.0/examples/wifi/wifi.ino +38 -0
- pytest_embedded_arduino_cli-0.2.0/pyproject.toml +31 -0
- pytest_embedded_arduino_cli-0.2.0/src/pytest_embedded_arduino_cli/__init__.py +6 -0
- pytest_embedded_arduino_cli-0.2.0/src/pytest_embedded_arduino_cli/app.py +198 -0
- pytest_embedded_arduino_cli-0.2.0/src/pytest_embedded_arduino_cli/flasher.py +54 -0
- pytest_embedded_arduino_cli-0.2.0/src/pytest_embedded_arduino_cli/plugin.py +233 -0
- pytest_embedded_arduino_cli-0.2.0/src/pytest_embedded_arduino_cli/serial.py +46 -0
- pytest_embedded_arduino_cli-0.2.0/tests/conftest.py +1 -0
- pytest_embedded_arduino_cli-0.2.0/tests/test_app.py +168 -0
- pytest_embedded_arduino_cli-0.2.0/tests/test_flasher.py +34 -0
- pytest_embedded_arduino_cli-0.2.0/tests/test_plugin.py +219 -0
- pytest_embedded_arduino_cli-0.2.0/tools/prepare_release.py +88 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version:
|
|
7
|
+
description: "Release version (X.Y.Z)"
|
|
8
|
+
required: true
|
|
9
|
+
publish_pypi:
|
|
10
|
+
description: "Publish package to PyPI"
|
|
11
|
+
required: true
|
|
12
|
+
type: boolean
|
|
13
|
+
default: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
prepare:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
permissions:
|
|
19
|
+
contents: write
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
|
|
27
|
+
- name: Setup Python
|
|
28
|
+
uses: actions/setup-python@v5
|
|
29
|
+
with:
|
|
30
|
+
python-version-file: ".python-version"
|
|
31
|
+
|
|
32
|
+
- name: Install uv
|
|
33
|
+
uses: astral-sh/setup-uv@v6
|
|
34
|
+
|
|
35
|
+
- name: Run release preparation
|
|
36
|
+
run: uv run python tools/prepare_release.py --version "${{ github.event.inputs.version }}"
|
|
37
|
+
|
|
38
|
+
- name: Run tests
|
|
39
|
+
run: uv run pytest tests
|
|
40
|
+
|
|
41
|
+
- name: Build package
|
|
42
|
+
run: uv build
|
|
43
|
+
|
|
44
|
+
- name: Commit release changes
|
|
45
|
+
run: |
|
|
46
|
+
git config user.name "github-actions[bot]"
|
|
47
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
48
|
+
git add pyproject.toml src/pytest_embedded_arduino_cli/__init__.py CHANGELOG.md
|
|
49
|
+
git commit -m "chore(release): v${{ github.event.inputs.version }}"
|
|
50
|
+
|
|
51
|
+
- name: Create tag
|
|
52
|
+
run: git tag "v${{ github.event.inputs.version }}"
|
|
53
|
+
|
|
54
|
+
- name: Push commit and tag
|
|
55
|
+
run: |
|
|
56
|
+
git push origin HEAD
|
|
57
|
+
git push origin "v${{ github.event.inputs.version }}"
|
|
58
|
+
|
|
59
|
+
create_github_release:
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
needs: prepare
|
|
62
|
+
permissions:
|
|
63
|
+
contents: write
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- name: Checkout tag
|
|
67
|
+
uses: actions/checkout@v4
|
|
68
|
+
with:
|
|
69
|
+
ref: "v${{ github.event.inputs.version }}"
|
|
70
|
+
fetch-depth: 0
|
|
71
|
+
|
|
72
|
+
- name: Build release body from CHANGELOG
|
|
73
|
+
run: |
|
|
74
|
+
VERSION="${{ github.event.inputs.version }}" python - <<'PY'
|
|
75
|
+
import os
|
|
76
|
+
import subprocess
|
|
77
|
+
from pathlib import Path
|
|
78
|
+
|
|
79
|
+
version = os.environ["VERSION"]
|
|
80
|
+
current_tag = f"v{version}"
|
|
81
|
+
|
|
82
|
+
changelog = Path("CHANGELOG.md").read_text(encoding="utf-8").splitlines()
|
|
83
|
+
section_header = f"## {version}"
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
start = changelog.index(section_header)
|
|
87
|
+
except ValueError as exc:
|
|
88
|
+
raise SystemExit(f"Version section {section_header} not found in CHANGELOG.md") from exc
|
|
89
|
+
|
|
90
|
+
end = len(changelog)
|
|
91
|
+
for i in range(start + 1, len(changelog)):
|
|
92
|
+
if changelog[i].startswith("## "):
|
|
93
|
+
end = i
|
|
94
|
+
break
|
|
95
|
+
|
|
96
|
+
section = "\n".join(changelog[start:end]).strip()
|
|
97
|
+
body = section + "\n\nRepository: https://github.com/tanakamasayuki/pytest-embedded-arduino-cli"
|
|
98
|
+
|
|
99
|
+
tags = (
|
|
100
|
+
subprocess.check_output(
|
|
101
|
+
["git", "tag", "--list", "v*", "--sort=v:refname"],
|
|
102
|
+
text=True,
|
|
103
|
+
)
|
|
104
|
+
.strip()
|
|
105
|
+
.splitlines()
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
prev_tag = ""
|
|
109
|
+
for i, tag in enumerate(tags):
|
|
110
|
+
if tag == current_tag and i > 0:
|
|
111
|
+
prev_tag = tags[i - 1]
|
|
112
|
+
break
|
|
113
|
+
|
|
114
|
+
if prev_tag:
|
|
115
|
+
body += (
|
|
116
|
+
"\n\nFull Changelog: "
|
|
117
|
+
"https://github.com/tanakamasayuki/pytest-embedded-arduino-cli/compare/"
|
|
118
|
+
f"{prev_tag}...{current_tag}"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
Path("release_body.md").write_text(body + "\n", encoding="utf-8")
|
|
122
|
+
PY
|
|
123
|
+
|
|
124
|
+
- name: Create GitHub Release
|
|
125
|
+
uses: softprops/action-gh-release@v2
|
|
126
|
+
with:
|
|
127
|
+
tag_name: "v${{ github.event.inputs.version }}"
|
|
128
|
+
body_path: release_body.md
|
|
129
|
+
generate_release_notes: false
|
|
130
|
+
|
|
131
|
+
publish_pypi:
|
|
132
|
+
runs-on: ubuntu-latest
|
|
133
|
+
needs: prepare
|
|
134
|
+
if: ${{ github.event.inputs.publish_pypi == 'true' }}
|
|
135
|
+
permissions:
|
|
136
|
+
id-token: write
|
|
137
|
+
contents: read
|
|
138
|
+
|
|
139
|
+
steps:
|
|
140
|
+
- name: Checkout tag
|
|
141
|
+
uses: actions/checkout@v4
|
|
142
|
+
with:
|
|
143
|
+
ref: "v${{ github.event.inputs.version }}"
|
|
144
|
+
|
|
145
|
+
- name: Setup Python
|
|
146
|
+
uses: actions/setup-python@v5
|
|
147
|
+
with:
|
|
148
|
+
python-version-file: ".python-version"
|
|
149
|
+
|
|
150
|
+
- name: Install uv
|
|
151
|
+
uses: astral-sh/setup-uv@v6
|
|
152
|
+
|
|
153
|
+
- name: Build package
|
|
154
|
+
run: uv build
|
|
155
|
+
|
|
156
|
+
- name: Publish to PyPI (Trusted Publishing)
|
|
157
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Setup Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version-file: ".python-version"
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v6
|
|
24
|
+
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: uv run pytest tests
|
|
27
|
+
|
|
28
|
+
- name: Build package
|
|
29
|
+
run: uv build
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.so
|
|
5
|
+
.Python
|
|
6
|
+
|
|
7
|
+
# Build / packaging
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
.eggs/
|
|
12
|
+
pip-wheel-metadata/
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
|
|
19
|
+
# Test / tooling caches
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.coverage
|
|
22
|
+
.coverage.*
|
|
23
|
+
htmlcov/
|
|
24
|
+
.mypy_cache/
|
|
25
|
+
.ruff_cache/
|
|
26
|
+
|
|
27
|
+
# IDE / OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
.idea/
|
|
30
|
+
.vscode/
|
|
31
|
+
|
|
32
|
+
# Local dependency locks
|
|
33
|
+
uv.lock
|
|
34
|
+
|
|
35
|
+
# Arduino CLI build outputs inside sketch directories
|
|
36
|
+
examples/**/build/
|
|
37
|
+
tests/**/build/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TANAKA Masayuki
|
|
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,229 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pytest-embedded-arduino-cli
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A pytest plugin to test Arduino projects using pytest-embedded and arduino-cli
|
|
5
|
+
Project-URL: Homepage, https://github.com/tanakamasayuki/pytest-embedded-arduino-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/tanakamasayuki/pytest-embedded-arduino-cli
|
|
7
|
+
Author: TANAKA Masayuki
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Requires-Dist: pytest-embedded-serial>=2.0
|
|
12
|
+
Requires-Dist: pytest-embedded>=2.0
|
|
13
|
+
Requires-Dist: pytest>=8
|
|
14
|
+
Requires-Dist: pyyaml>=6.0
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# pytest-embedded-arduino-cli
|
|
18
|
+
|
|
19
|
+
[日本語版 README](README.ja.md)
|
|
20
|
+
|
|
21
|
+
A pytest plugin to test Arduino projects using `pytest-embedded` and `arduino-cli`.
|
|
22
|
+
|
|
23
|
+
## Overview
|
|
24
|
+
|
|
25
|
+
`pytest-embedded-arduino-cli` is a small plugin that keeps `pytest-embedded`'s generic DUT / serial / expect flow and replaces Arduino-specific build and upload with `arduino-cli`.
|
|
26
|
+
|
|
27
|
+
This package does not depend on `pytest-embedded-arduino`. It is intended to stay generic enough to work well for Arduino projects beyond ESP32-specific assumptions.
|
|
28
|
+
|
|
29
|
+
## Design
|
|
30
|
+
|
|
31
|
+
- Build with `arduino-cli compile`
|
|
32
|
+
- Upload with `arduino-cli upload`
|
|
33
|
+
- Use `pytest-embedded` as the runtime foundation
|
|
34
|
+
- Avoid `EspSerial` and ESP-specific flashing services
|
|
35
|
+
- Resolve sketch settings from `sketch.yaml` and `--profile`
|
|
36
|
+
- Treat the test file directory as the sketch directory
|
|
37
|
+
|
|
38
|
+
## Setup
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
uv init
|
|
42
|
+
uv add pytest-embedded-arduino-cli
|
|
43
|
+
uv sync
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Runtime dependencies include:
|
|
47
|
+
|
|
48
|
+
- `pytest`
|
|
49
|
+
- `pytest-embedded`
|
|
50
|
+
- `pytest-embedded-serial`
|
|
51
|
+
- `PyYAML`
|
|
52
|
+
|
|
53
|
+
## Requirements
|
|
54
|
+
|
|
55
|
+
- `arduino-cli` available in `PATH`
|
|
56
|
+
- Installed Arduino board core(s)
|
|
57
|
+
- A serial port accessible from the host when running hardware tests
|
|
58
|
+
|
|
59
|
+
## Project Layout
|
|
60
|
+
|
|
61
|
+
The expected layout is one sketch directory per test app.
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
tests/
|
|
65
|
+
my_app/
|
|
66
|
+
sketch.yaml
|
|
67
|
+
my_app.ino
|
|
68
|
+
test_my_app.py
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
When pytest runs a specific `.py` file, this plugin treats that file's directory as the sketch directory. Build settings are resolved from the nearest `sketch.yaml`.
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
Build, upload, and run tests:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv run pytest tests/my_app --port /dev/ttyACM0
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Select an Arduino CLI profile from `sketch.yaml`:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
uv run pytest tests/my_app --profile esp32s3 --port /dev/ttyACM0
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Build only:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv run pytest tests/my_app --run-mode=build
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Upload and test against an already-built image:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
uv run pytest tests/my_app --run-mode=test --port /dev/ttyACM0
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`--run-mode=test` skips compile, reuses the existing build output, uploads it, and then runs the test.
|
|
100
|
+
|
|
101
|
+
Run this package's own tests:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
uv run pytest
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Main Options
|
|
108
|
+
|
|
109
|
+
- `--run-mode=all|build|test`
|
|
110
|
+
- `--profile`
|
|
111
|
+
|
|
112
|
+
Use `pytest-embedded` standard options for runtime control, such as:
|
|
113
|
+
|
|
114
|
+
- `--port`
|
|
115
|
+
- `--flash-port`
|
|
116
|
+
- `--baud`
|
|
117
|
+
- `--embedded-services`
|
|
118
|
+
|
|
119
|
+
`pytest-embedded-serial` is installed as a normal dependency so hardware tests can use the serial service without extra package installation.
|
|
120
|
+
If `--embedded-services` is not specified, this plugin enables `serial` by default.
|
|
121
|
+
|
|
122
|
+
For profile-specific serial ports, the plugin resolves ports in this order:
|
|
123
|
+
|
|
124
|
+
1. `--flash-port`
|
|
125
|
+
2. `--port`
|
|
126
|
+
3. `TEST_SERIAL_PORT_<PROFILE>`
|
|
127
|
+
4. `TEST_SERIAL_PORT`
|
|
128
|
+
|
|
129
|
+
Example:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
export TEST_SERIAL_PORT_ESP32S3=/dev/ttyUSB1
|
|
133
|
+
uv run pytest tests/my_app --profile esp32s3
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
If `--profile` is omitted, the plugin uses the resolved profile from `sketch.yaml`, including `default_profile`.
|
|
137
|
+
|
|
138
|
+
For compile-time defines, place a `build_config.toml` in the sketch directory:
|
|
139
|
+
|
|
140
|
+
```toml
|
|
141
|
+
[defines]
|
|
142
|
+
TEST_WIFI_SSID = "WIFI_SSID"
|
|
143
|
+
TEST_WIFI_PASSWORD = "WIFI_PASSWORD"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Here, the left side is the environment variable name and the right side is the C/C++ define name.
|
|
147
|
+
For example, `TEST_WIFI_SSID` becomes `-DWIFI_SSID="..."` at compile time.
|
|
148
|
+
|
|
149
|
+
Set values before running pytest:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
export TEST_WIFI_SSID=my-ssid
|
|
153
|
+
export TEST_WIFI_PASSWORD=my-password
|
|
154
|
+
uv run pytest tests/my_app
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
If an environment variable is missing, the plugin still passes the define with an empty string value.
|
|
158
|
+
This allows the test or sketch code to decide how to handle missing settings.
|
|
159
|
+
|
|
160
|
+
For command visibility, follow pytest's standard verbosity:
|
|
161
|
+
|
|
162
|
+
- `-v` shows the `arduino-cli compile` / `arduino-cli upload` command line
|
|
163
|
+
- `-vv` also shows execution context such as `cwd`, `sketch_dir`, `build_path`, `profile`, and `port`
|
|
164
|
+
|
|
165
|
+
## Example
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
def test_hello(dut):
|
|
169
|
+
dut.expect_exact("hello from arduino")
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```cpp
|
|
173
|
+
void setup() {
|
|
174
|
+
Serial.begin(115200);
|
|
175
|
+
delay(1000);
|
|
176
|
+
Serial.println("hello from arduino");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
void loop() {}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Additional sample:
|
|
183
|
+
|
|
184
|
+
- `examples/wifi`
|
|
185
|
+
- Connects to Wi-Fi on ESP32/ESP32-S3
|
|
186
|
+
- Includes `uno` as a skip example for a non-Wi-Fi profile
|
|
187
|
+
- Expects `TEST_WIFI_SSID` and `TEST_WIFI_PASSWORD`
|
|
188
|
+
- Verifies that the board prints `WIFI_OK <ip-address>`
|
|
189
|
+
|
|
190
|
+
## What This Plugin Does Not Try To Be
|
|
191
|
+
|
|
192
|
+
- A drop-in replacement for `pytest-embedded-arduino`
|
|
193
|
+
- An ESP-specific flashing layer
|
|
194
|
+
- A board auto-discovery tool
|
|
195
|
+
|
|
196
|
+
## Future Extensions
|
|
197
|
+
|
|
198
|
+
- Board-family-specific upload strategies
|
|
199
|
+
- Smarter artifact discovery
|
|
200
|
+
- Serial reset / monitor helpers
|
|
201
|
+
- Multi-device support
|
|
202
|
+
- Optional `fqbn` or sketch path overrides
|
|
203
|
+
|
|
204
|
+
## Release
|
|
205
|
+
|
|
206
|
+
This repository uses GitHub Actions for releases.
|
|
207
|
+
|
|
208
|
+
Before triggering a release:
|
|
209
|
+
|
|
210
|
+
- Update the `## Unreleased` section in `CHANGELOG.md`
|
|
211
|
+
- Make sure `uv run pytest tests` passes locally if needed
|
|
212
|
+
|
|
213
|
+
Release flow:
|
|
214
|
+
|
|
215
|
+
1. Open GitHub Actions
|
|
216
|
+
2. Run the `Release` workflow manually
|
|
217
|
+
3. Enter the release version such as `0.1.0`
|
|
218
|
+
4. Choose whether to publish to PyPI
|
|
219
|
+
|
|
220
|
+
The workflow will:
|
|
221
|
+
|
|
222
|
+
- Update versions in `pyproject.toml` and `src/pytest_embedded_arduino_cli/__init__.py`
|
|
223
|
+
- Move `CHANGELOG.md` unreleased entries into `## <version>`
|
|
224
|
+
- Run tests and build the package
|
|
225
|
+
- Commit the release changes and create tag `v<version>`
|
|
226
|
+
- Create a GitHub Release
|
|
227
|
+
- Publish to PyPI when enabled
|
|
228
|
+
|
|
229
|
+
PyPI publishing is configured for Trusted Publishing via GitHub Actions.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# pytest-embedded-arduino-cli
|
|
2
|
+
|
|
3
|
+
[English README](README.md)
|
|
4
|
+
|
|
5
|
+
`pytest-embedded` と `arduino-cli` を使って Arduino プロジェクトをテストするための pytest plugin です。
|
|
6
|
+
|
|
7
|
+
## 概要
|
|
8
|
+
|
|
9
|
+
`pytest-embedded-arduino-cli` は、`pytest-embedded` の汎用的な DUT / serial / expect の流れを活かしつつ、Arduino 向けの build / upload を `arduino-cli` に置き換える小さな plugin です。
|
|
10
|
+
|
|
11
|
+
このパッケージは `pytest-embedded-arduino` には依存しません。ESP32 固有の前提に寄せず、より広い Arduino プロジェクトで使いやすい構成を目指しています。
|
|
12
|
+
|
|
13
|
+
## 設計方針
|
|
14
|
+
|
|
15
|
+
- build は `arduino-cli compile`
|
|
16
|
+
- upload は `arduino-cli upload`
|
|
17
|
+
- test runtime は `pytest-embedded` を土台にする
|
|
18
|
+
- `EspSerial` や ESP 固有の flashing service は使わない
|
|
19
|
+
- sketch 設定は `sketch.yaml` と `--profile` から解決する
|
|
20
|
+
- テストファイルのあるディレクトリを sketch ディレクトリとして扱う
|
|
21
|
+
|
|
22
|
+
## セットアップ
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uv init
|
|
26
|
+
uv add pytest-embedded-arduino-cli
|
|
27
|
+
uv sync
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
通常依存として次を含みます。
|
|
31
|
+
|
|
32
|
+
- `pytest`
|
|
33
|
+
- `pytest-embedded`
|
|
34
|
+
- `pytest-embedded-serial`
|
|
35
|
+
- `PyYAML`
|
|
36
|
+
|
|
37
|
+
## 前提条件
|
|
38
|
+
|
|
39
|
+
- `arduino-cli` が `PATH` に入っていること
|
|
40
|
+
- 必要な Arduino board core がインストール済みであること
|
|
41
|
+
- 実機テスト時にホストからアクセスできる serial port があること
|
|
42
|
+
|
|
43
|
+
## 想定レイアウト
|
|
44
|
+
|
|
45
|
+
基本は 1 つのテストアプリごとに 1 つの sketch ディレクトリを想定します。
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
tests/
|
|
49
|
+
my_app/
|
|
50
|
+
sketch.yaml
|
|
51
|
+
my_app.ino
|
|
52
|
+
test_my_app.py
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
pytest が特定の `.py` を実行したとき、この plugin はそのファイルがあるディレクトリを sketch ディレクトリとして扱います。build 設定は最も近い `sketch.yaml` から解決します。
|
|
56
|
+
|
|
57
|
+
## 使い方
|
|
58
|
+
|
|
59
|
+
build・upload・test をまとめて実行する例:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv run pytest tests/my_app --port /dev/ttyACM0
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`sketch.yaml` の profile を選ぶ例:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv run pytest tests/my_app --profile esp32s3 --port /dev/ttyACM0
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
build のみ:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
uv run pytest tests/my_app --run-mode=build
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
既存 build artifact を使って upload してから test:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
uv run pytest tests/my_app --run-mode=test --port /dev/ttyACM0
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`--run-mode=test` は compile を行わず、既存 build 出力を使って upload してから test を実行します。
|
|
84
|
+
|
|
85
|
+
このパッケージ自身のテストを実行する例:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv run pytest
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 主な option
|
|
92
|
+
|
|
93
|
+
- `--run-mode=all|build|test`
|
|
94
|
+
- `--profile`
|
|
95
|
+
|
|
96
|
+
実行時の制御には `pytest-embedded` 標準 option を使います。主なものは次です。
|
|
97
|
+
|
|
98
|
+
- `--port`
|
|
99
|
+
- `--flash-port`
|
|
100
|
+
- `--baud`
|
|
101
|
+
- `--embedded-services`
|
|
102
|
+
|
|
103
|
+
`pytest-embedded-serial` は通常依存に含めているため、実機テストで serial service を追加インストールなしで使えます。
|
|
104
|
+
`--embedded-services` を指定しない場合、この plugin は `serial` をデフォルトで有効化します。
|
|
105
|
+
|
|
106
|
+
profile ごとの serial port は次の順で解決します。
|
|
107
|
+
|
|
108
|
+
1. `--flash-port`
|
|
109
|
+
2. `--port`
|
|
110
|
+
3. `TEST_SERIAL_PORT_<PROFILE>`
|
|
111
|
+
4. `TEST_SERIAL_PORT`
|
|
112
|
+
|
|
113
|
+
例:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
export TEST_SERIAL_PORT_ESP32S3=/dev/ttyUSB1
|
|
117
|
+
uv run pytest tests/my_app --profile esp32s3
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`--profile` を省略した場合でも、plugin は `sketch.yaml` から解決した profile を使います。`default_profile` もこの対象です。
|
|
121
|
+
|
|
122
|
+
compile-time define を渡したい場合は、sketch ディレクトリに `build_config.toml` を置きます。
|
|
123
|
+
|
|
124
|
+
```toml
|
|
125
|
+
[defines]
|
|
126
|
+
TEST_WIFI_SSID = "WIFI_SSID"
|
|
127
|
+
TEST_WIFI_PASSWORD = "WIFI_PASSWORD"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
左側は環境変数名、右側は C/C++ 側で使う define 名です。
|
|
131
|
+
例えば `TEST_WIFI_SSID` は compile 時に `-DWIFI_SSID="..."` に変換されます。
|
|
132
|
+
|
|
133
|
+
実行前に対応する環境変数を設定しておくと、plugin が `arduino-cli compile --build-property build.extra_flags=...` に変換して渡します。
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
export TEST_WIFI_SSID=my-ssid
|
|
137
|
+
export TEST_WIFI_PASSWORD=my-password
|
|
138
|
+
uv run pytest tests/my_app
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
環境変数が未設定でも、その define には空文字が渡されます。
|
|
142
|
+
未設定をどう扱うかは、テスト側または sketch 側で判断できます。
|
|
143
|
+
|
|
144
|
+
## verbosity とログ
|
|
145
|
+
|
|
146
|
+
コマンド表示には pytest 標準の verbosity を使います。
|
|
147
|
+
|
|
148
|
+
- `-v`
|
|
149
|
+
- `arduino-cli compile` / `arduino-cli upload` の実行コマンドを表示
|
|
150
|
+
- `-vv`
|
|
151
|
+
- 上記に加えて `cwd`、`sketch_dir`、`build_path`、`profile`、`port` なども表示
|
|
152
|
+
|
|
153
|
+
## 例
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
def test_hello(dut):
|
|
157
|
+
dut.expect_exact("hello from arduino")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
```cpp
|
|
161
|
+
void setup() {
|
|
162
|
+
Serial.begin(115200);
|
|
163
|
+
delay(1000);
|
|
164
|
+
Serial.println("hello from arduino");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
void loop() {}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
追加サンプル:
|
|
171
|
+
|
|
172
|
+
- `examples/wifi`
|
|
173
|
+
- ESP32 / ESP32-S3 で Wi-Fi 接続を行う
|
|
174
|
+
- Wi-Fi 非対応 profile の例として `uno` では skip する
|
|
175
|
+
- `TEST_WIFI_SSID` と `TEST_WIFI_PASSWORD` を使う
|
|
176
|
+
- ボードが `WIFI_OK <ip-address>` を出力することを検証する
|
|
177
|
+
|
|
178
|
+
## この plugin が目指していないもの
|
|
179
|
+
|
|
180
|
+
- `pytest-embedded-arduino` の drop-in replacement
|
|
181
|
+
- ESP 固有の flashing layer
|
|
182
|
+
- board 自動検出ツール
|
|
183
|
+
|
|
184
|
+
## 今後の拡張候補
|
|
185
|
+
|
|
186
|
+
- board family ごとの upload strategy
|
|
187
|
+
- artifact 探索の改善
|
|
188
|
+
- serial reset / monitor helper
|
|
189
|
+
- 複数デバイス対応
|
|
190
|
+
- `fqbn` や sketch path の override
|
|
191
|
+
|
|
192
|
+
## リリース方法
|
|
193
|
+
|
|
194
|
+
このリポジトリは GitHub Actions ベースでリリースします。
|
|
195
|
+
|
|
196
|
+
リリース前に最低限やること:
|
|
197
|
+
|
|
198
|
+
- `CHANGELOG.md` の `## Unreleased` を更新する
|
|
199
|
+
- 必要ならローカルで `uv run pytest tests` を通しておく
|
|
200
|
+
|
|
201
|
+
リリース手順:
|
|
202
|
+
|
|
203
|
+
1. GitHub Actions を開く
|
|
204
|
+
2. `Release` workflow を手動実行する
|
|
205
|
+
3. `0.1.0` のような version を入力する
|
|
206
|
+
4. PyPI に publish するかを選ぶ
|
|
207
|
+
|
|
208
|
+
workflow が行うこと:
|
|
209
|
+
|
|
210
|
+
- `pyproject.toml` と `src/pytest_embedded_arduino_cli/__init__.py` の version 更新
|
|
211
|
+
- `CHANGELOG.md` の `## Unreleased` を `## <version>` に反映
|
|
212
|
+
- テストとパッケージ build の実行
|
|
213
|
+
- release 用 commit と `v<version>` tag の作成
|
|
214
|
+
- GitHub Release の作成
|
|
215
|
+
- 必要に応じて PyPI への publish
|
|
216
|
+
|
|
217
|
+
PyPI publish は GitHub Actions の Trusted Publishing を前提にしています。
|