chore: import upstream snapshot with attribution
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
# Tests for .github/scripts
|
||||
|
||||
This directory contains comprehensive tests for the GitHub workflow scripts using Python's built-in testing framework.
|
||||
|
||||
## Requirements
|
||||
|
||||
**No external dependencies required!**
|
||||
|
||||
This test suite uses:
|
||||
|
||||
- `unittest` - Python's built-in testing framework
|
||||
- `tomllib` - Python 3.11+ built-in TOML parser
|
||||
|
||||
For Python < 3.11, the `toml` package is used as a fallback.
|
||||
|
||||
## Running Tests
|
||||
|
||||
### Run all tests
|
||||
|
||||
```bash
|
||||
cd .github/scripts/tests
|
||||
python3 -m unittest discover -v
|
||||
```
|
||||
|
||||
### Run a specific test file
|
||||
|
||||
```bash
|
||||
python3 -m unittest test_get_pyproject_version -v
|
||||
```
|
||||
|
||||
### Run a specific test class
|
||||
|
||||
```bash
|
||||
python3 -m unittest test_get_pyproject_version.TestGetPyprojectVersion -v
|
||||
```
|
||||
|
||||
### Run a specific test method
|
||||
|
||||
```bash
|
||||
python3 -m unittest test_get_pyproject_version.TestGetPyprojectVersion.test_matching_versions -v
|
||||
```
|
||||
|
||||
### Run tests directly from the test file
|
||||
|
||||
```bash
|
||||
python3 test_get_pyproject_version.py
|
||||
```
|
||||
|
||||
## Test Structure
|
||||
|
||||
### test_get_pyproject_version.py
|
||||
|
||||
Comprehensive tests for `get_pyproject_version.py` covering:
|
||||
|
||||
- ✅ **Version matching**: Tests successful version validation
|
||||
- ✅ **Version mismatch**: Tests error handling when versions don't match
|
||||
- ✅ **Missing version**: Tests handling of pyproject.toml without version field
|
||||
- ✅ **Missing project section**: Tests handling of pyproject.toml without project section
|
||||
- ✅ **File not found**: Tests handling of non-existent files
|
||||
- ✅ **Malformed TOML**: Tests handling of invalid TOML syntax
|
||||
- ✅ **Argument validation**: Tests proper argument count validation
|
||||
- ✅ **Semantic versioning**: Tests various semantic version formats
|
||||
- ✅ **Pre-release tags**: Tests versions with alpha, beta, rc tags
|
||||
- ✅ **Build metadata**: Tests versions with build metadata
|
||||
- ✅ **Edge cases**: Tests empty versions and other edge cases
|
||||
|
||||
**Total Tests**: 17+ test cases covering all functionality
|
||||
|
||||
## Best Practices Implemented
|
||||
|
||||
1. **Fixture Management**: Uses `setUp()` and `tearDown()` for clean test isolation
|
||||
2. **Helper Methods**: Provides reusable helpers for creating test fixtures
|
||||
3. **Temporary Files**: Uses `tempfile` for file creation with proper cleanup
|
||||
4. **Comprehensive Coverage**: Tests happy paths, error conditions, and edge cases
|
||||
5. **Clear Documentation**: Each test has a descriptive docstring
|
||||
6. **Output Capture**: Uses `unittest.mock.patch` and `StringIO` to test stdout/stderr
|
||||
7. **Exit Code Validation**: Properly tests script exit codes with `assertRaises(SystemExit)`
|
||||
8. **Type Hints**: Uses type hints in helper methods for clarity
|
||||
9. **PEP 8 Compliance**: Follows Python style guidelines
|
||||
10. **Zero External Dependencies**: Uses only Python standard library
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
These tests can be integrated into GitHub Actions workflows with no additional dependencies:
|
||||
|
||||
```yaml
|
||||
- name: Run .github scripts tests
|
||||
run: |
|
||||
cd .github/scripts/tests
|
||||
python3 -m unittest discover -v
|
||||
```
|
||||
|
||||
## Test Output Example
|
||||
|
||||
```
|
||||
test_empty_version_string (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test handling of empty version string. ... ok
|
||||
test_file_not_found (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test handling of non-existent pyproject.toml file. ... ok
|
||||
test_malformed_toml (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test handling of malformed TOML file. ... ok
|
||||
test_matching_versions (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test that matching versions result in success. ... ok
|
||||
test_missing_project_section (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test handling of pyproject.toml without a project section. ... ok
|
||||
test_missing_version_field (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test handling of pyproject.toml without a version field. ... ok
|
||||
test_no_arguments (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test that providing no arguments results in usage error. ... ok
|
||||
test_semantic_version_0_0_1 (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test semantic version 0.0.1. ... ok
|
||||
test_semantic_version_1_0_0 (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test semantic version 1.0.0. ... ok
|
||||
test_semantic_version_10_20_30 (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test semantic version 10.20.30. ... ok
|
||||
test_semantic_version_alpha (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test semantic version with alpha tag. ... ok
|
||||
test_semantic_version_beta (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test semantic version with beta tag. ... ok
|
||||
test_semantic_version_rc_with_build (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test semantic version with rc and build metadata. ... ok
|
||||
test_too_few_arguments (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test that providing too few arguments results in usage error. ... ok
|
||||
test_too_many_arguments (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test that providing too many arguments results in usage error. ... ok
|
||||
test_version_mismatch (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test that mismatched versions result in failure with appropriate error message. ... ok
|
||||
test_version_with_build_metadata (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test matching versions with build metadata. ... ok
|
||||
test_version_with_prerelease_tags (test_get_pyproject_version.TestGetPyprojectVersion)
|
||||
Test matching versions with pre-release tags like alpha, beta, rc. ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 18 tests in 0.XXXs
|
||||
|
||||
OK
|
||||
```
|
||||
@@ -0,0 +1 @@
|
||||
"""Tests for .github/scripts."""
|
||||
@@ -0,0 +1,39 @@
|
||||
"""Regression tests for cua-cloud release automation wiring."""
|
||||
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
|
||||
|
||||
class TestCuaCloudReleaseWiring(unittest.TestCase):
|
||||
"""Verify cua-cloud is wired into the release automation."""
|
||||
|
||||
def read(self, relative_path: str) -> str:
|
||||
return (REPO_ROOT / relative_path).read_text()
|
||||
|
||||
def test_release_on_merge_tracks_cua_cloud(self) -> None:
|
||||
workflow = self.read(".github/workflows/release-on-merge.yml")
|
||||
|
||||
self.assertIn('["libs/python/cua-cloud/"]="pypi/cloud"', workflow)
|
||||
|
||||
def test_release_bump_version_supports_cua_cloud(self) -> None:
|
||||
workflow = self.read(".github/workflows/release-bump-version.yml")
|
||||
|
||||
self.assertIn("- pypi/cloud", workflow)
|
||||
self.assertIn('"pypi/cloud")', workflow)
|
||||
self.assertIn('echo "directory=libs/python/cua-cloud" >> $GITHUB_OUTPUT', workflow)
|
||||
|
||||
def test_unreleased_digest_tracks_cua_cloud(self) -> None:
|
||||
workflow = self.read(".github/workflows/release-unreleased-digest.yml")
|
||||
|
||||
self.assertIn('SERVICE_TAG_DIR["pypi/cloud"]="cloud-v|libs/python/cua-cloud/"', workflow)
|
||||
|
||||
def test_package_release_files_exist(self) -> None:
|
||||
self.assertTrue((REPO_ROOT / ".github/workflows/cd-py-cloud.yml").exists())
|
||||
self.assertTrue((REPO_ROOT / "libs/python/cua-cloud/.bumpversion.cfg").exists())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,68 @@
|
||||
"""Regression tests for cua-driver-rs release and PyPI wiring."""
|
||||
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
|
||||
|
||||
class TestCuaDriverReleaseWiring(unittest.TestCase):
|
||||
"""Verify cua-driver-rs releases feed the Python cua-driver publisher."""
|
||||
|
||||
def read(self, relative_path: str) -> str:
|
||||
return (REPO_ROOT / relative_path).read_text()
|
||||
|
||||
def test_python_publish_follows_rust_workflow_run(self) -> None:
|
||||
workflow = self.read(".github/workflows/cd-py-cua-driver.yml")
|
||||
|
||||
self.assertIn('workflows: ["CD: Cua Driver (cross-platform)"]', workflow)
|
||||
self.assertNotIn("branches:\n - main", workflow)
|
||||
self.assertIn('github.event.workflow_run.conclusion != \'cancelled\'', workflow)
|
||||
self.assertIn('gh release view "$TAG" --repo "$GITHUB_REPOSITORY"', workflow)
|
||||
|
||||
def test_python_publish_defaults_to_current_rust_version(self) -> None:
|
||||
workflow = self.read(".github/workflows/cd-py-cua-driver.yml")
|
||||
|
||||
self.assertIn("required: false", workflow)
|
||||
self.assertIn('default: ""', workflow)
|
||||
self.assertIn("libs/cua-driver/rust/Cargo.toml", workflow)
|
||||
|
||||
def test_python_publish_builds_linux_arm64_wheel(self) -> None:
|
||||
workflow = self.read(".github/workflows/cd-py-cua-driver.yml")
|
||||
|
||||
self.assertIn("os: ubuntu-24.04-arm", workflow)
|
||||
self.assertIn("arch: arm64", workflow)
|
||||
|
||||
def test_release_on_merge_tracks_rust_driver(self) -> None:
|
||||
workflow = self.read(".github/workflows/release-on-merge.yml")
|
||||
|
||||
self.assertIn('["libs/cua-driver/rust/"]="cua-driver-rs"', workflow)
|
||||
|
||||
def test_release_reminder_tracks_rust_driver(self) -> None:
|
||||
workflow = self.read(".github/workflows/ci-release-reminder.yml")
|
||||
|
||||
self.assertIn('["libs/cua-driver/rust/"]="cua-driver-rs"', workflow)
|
||||
self.assertIn("cua-driver desktop release validation", workflow)
|
||||
self.assertIn("e2e-rust-windows.yml", workflow)
|
||||
self.assertIn("scripts/ci/macos/run-rust-e2e.sh", workflow)
|
||||
self.assertIn("e2e-rust-linux.yml", workflow)
|
||||
self.assertIn("e2e-rust-linux-wayland.yml", workflow)
|
||||
|
||||
def test_unreleased_digest_tracks_rust_driver(self) -> None:
|
||||
workflow = self.read(".github/workflows/release-unreleased-digest.yml")
|
||||
|
||||
self.assertIn(
|
||||
'SERVICE_TAG_DIR["cua-driver-rs"]="cua-driver-rs-v|libs/cua-driver/rust/"',
|
||||
workflow,
|
||||
)
|
||||
|
||||
def test_rust_driver_bump_keeps_python_wrapper_version_synced(self) -> None:
|
||||
config = self.read("libs/cua-driver/rust/.bumpversion.cfg")
|
||||
|
||||
self.assertIn("[bumpversion:file:../python/pyproject.toml]", config)
|
||||
self.assertIn("[bumpversion:file:../python/src/cua_driver/__init__.py]", config)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,360 @@
|
||||
"""
|
||||
Comprehensive tests for get_pyproject_version.py script using unittest.
|
||||
|
||||
This test suite covers:
|
||||
- Version matching validation
|
||||
- Error handling for missing versions
|
||||
- Invalid input handling
|
||||
- File not found scenarios
|
||||
- Malformed TOML handling
|
||||
"""
|
||||
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
# Add parent directory to path to import the module
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
# Import after path is modified
|
||||
import get_pyproject_version
|
||||
|
||||
|
||||
class TestGetPyprojectVersion(unittest.TestCase):
|
||||
"""Test suite for get_pyproject_version.py functionality."""
|
||||
|
||||
def setUp(self):
|
||||
"""Reset sys.argv before each test."""
|
||||
self.original_argv = sys.argv.copy()
|
||||
|
||||
def tearDown(self):
|
||||
"""Restore sys.argv after each test."""
|
||||
sys.argv = self.original_argv
|
||||
|
||||
def create_pyproject_toml(self, version: str) -> Path:
|
||||
"""Helper to create a temporary pyproject.toml file with a given version."""
|
||||
temp_file = tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False)
|
||||
temp_file.write(
|
||||
f"""
|
||||
[project]
|
||||
name = "test-project"
|
||||
version = "{version}"
|
||||
description = "A test project"
|
||||
"""
|
||||
)
|
||||
temp_file.close()
|
||||
return Path(temp_file.name)
|
||||
|
||||
def create_pyproject_toml_no_version(self) -> Path:
|
||||
"""Helper to create a pyproject.toml without a version field."""
|
||||
temp_file = tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False)
|
||||
temp_file.write(
|
||||
"""
|
||||
[project]
|
||||
name = "test-project"
|
||||
description = "A test project without version"
|
||||
"""
|
||||
)
|
||||
temp_file.close()
|
||||
return Path(temp_file.name)
|
||||
|
||||
def create_pyproject_toml_no_project(self) -> Path:
|
||||
"""Helper to create a pyproject.toml without a project section."""
|
||||
temp_file = tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False)
|
||||
temp_file.write(
|
||||
"""
|
||||
[tool.poetry]
|
||||
name = "test-project"
|
||||
version = "1.0.0"
|
||||
"""
|
||||
)
|
||||
temp_file.close()
|
||||
return Path(temp_file.name)
|
||||
|
||||
def create_malformed_toml(self) -> Path:
|
||||
"""Helper to create a malformed TOML file."""
|
||||
temp_file = tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False)
|
||||
temp_file.write(
|
||||
"""
|
||||
[project
|
||||
name = "test-project
|
||||
version = "1.0.0"
|
||||
"""
|
||||
)
|
||||
temp_file.close()
|
||||
return Path(temp_file.name)
|
||||
|
||||
# Test: Successful version match
|
||||
def test_matching_versions(self):
|
||||
"""Test that matching versions result in success."""
|
||||
pyproject_file = self.create_pyproject_toml("1.2.3")
|
||||
|
||||
try:
|
||||
sys.argv = ["get_pyproject_version.py", str(pyproject_file), "1.2.3"]
|
||||
|
||||
# Capture stdout
|
||||
captured_output = StringIO()
|
||||
with patch("sys.stdout", captured_output):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 0)
|
||||
self.assertIn("✅ Version consistency check passed: 1.2.3", captured_output.getvalue())
|
||||
finally:
|
||||
pyproject_file.unlink()
|
||||
|
||||
# Test: Version mismatch
|
||||
def test_version_mismatch(self):
|
||||
"""Test that mismatched versions result in failure with appropriate error message."""
|
||||
pyproject_file = self.create_pyproject_toml("1.2.3")
|
||||
|
||||
try:
|
||||
sys.argv = ["get_pyproject_version.py", str(pyproject_file), "1.2.4"]
|
||||
|
||||
# Capture stderr
|
||||
captured_error = StringIO()
|
||||
with patch("sys.stderr", captured_error):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
error_output = captured_error.getvalue()
|
||||
self.assertIn("❌ Version mismatch detected!", error_output)
|
||||
self.assertIn("pyproject.toml version: 1.2.3", error_output)
|
||||
self.assertIn("Expected version: 1.2.4", error_output)
|
||||
self.assertIn("Please update pyproject.toml to version 1.2.4", error_output)
|
||||
finally:
|
||||
pyproject_file.unlink()
|
||||
|
||||
# Test: Missing version in pyproject.toml
|
||||
def test_missing_version_field(self):
|
||||
"""Test handling of pyproject.toml without a version field."""
|
||||
pyproject_file = self.create_pyproject_toml_no_version()
|
||||
|
||||
try:
|
||||
sys.argv = ["get_pyproject_version.py", str(pyproject_file), "1.0.0"]
|
||||
|
||||
captured_error = StringIO()
|
||||
with patch("sys.stderr", captured_error):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
self.assertIn("❌ ERROR: No version found in pyproject.toml", captured_error.getvalue())
|
||||
finally:
|
||||
pyproject_file.unlink()
|
||||
|
||||
# Test: Missing project section
|
||||
def test_missing_project_section(self):
|
||||
"""Test handling of pyproject.toml without a project section."""
|
||||
pyproject_file = self.create_pyproject_toml_no_project()
|
||||
|
||||
try:
|
||||
sys.argv = ["get_pyproject_version.py", str(pyproject_file), "1.0.0"]
|
||||
|
||||
captured_error = StringIO()
|
||||
with patch("sys.stderr", captured_error):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
self.assertIn("❌ ERROR: No version found in pyproject.toml", captured_error.getvalue())
|
||||
finally:
|
||||
pyproject_file.unlink()
|
||||
|
||||
# Test: File not found
|
||||
def test_file_not_found(self):
|
||||
"""Test handling of non-existent pyproject.toml file."""
|
||||
sys.argv = ["get_pyproject_version.py", "/nonexistent/pyproject.toml", "1.0.0"]
|
||||
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
|
||||
# Test: Malformed TOML
|
||||
def test_malformed_toml(self):
|
||||
"""Test handling of malformed TOML file."""
|
||||
pyproject_file = self.create_malformed_toml()
|
||||
|
||||
try:
|
||||
sys.argv = ["get_pyproject_version.py", str(pyproject_file), "1.0.0"]
|
||||
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
finally:
|
||||
pyproject_file.unlink()
|
||||
|
||||
# Test: Incorrect number of arguments - too few
|
||||
def test_too_few_arguments(self):
|
||||
"""Test that providing too few arguments results in usage error."""
|
||||
sys.argv = ["get_pyproject_version.py", "pyproject.toml"]
|
||||
|
||||
captured_error = StringIO()
|
||||
with patch("sys.stderr", captured_error):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
self.assertIn(
|
||||
"Usage: python get_pyproject_version.py <pyproject_path> <expected_version>",
|
||||
captured_error.getvalue(),
|
||||
)
|
||||
|
||||
# Test: Incorrect number of arguments - too many
|
||||
def test_too_many_arguments(self):
|
||||
"""Test that providing too many arguments results in usage error."""
|
||||
sys.argv = ["get_pyproject_version.py", "pyproject.toml", "1.0.0", "extra"]
|
||||
|
||||
captured_error = StringIO()
|
||||
with patch("sys.stderr", captured_error):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
self.assertIn(
|
||||
"Usage: python get_pyproject_version.py <pyproject_path> <expected_version>",
|
||||
captured_error.getvalue(),
|
||||
)
|
||||
|
||||
# Test: No arguments
|
||||
def test_no_arguments(self):
|
||||
"""Test that providing no arguments results in usage error."""
|
||||
sys.argv = ["get_pyproject_version.py"]
|
||||
|
||||
captured_error = StringIO()
|
||||
with patch("sys.stderr", captured_error):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
self.assertIn(
|
||||
"Usage: python get_pyproject_version.py <pyproject_path> <expected_version>",
|
||||
captured_error.getvalue(),
|
||||
)
|
||||
|
||||
# Test: Version with pre-release tags
|
||||
def test_version_with_prerelease_tags(self):
|
||||
"""Test matching versions with pre-release tags like alpha, beta, rc."""
|
||||
pyproject_file = self.create_pyproject_toml("1.2.3-rc.1")
|
||||
|
||||
try:
|
||||
sys.argv = ["get_pyproject_version.py", str(pyproject_file), "1.2.3-rc.1"]
|
||||
|
||||
captured_output = StringIO()
|
||||
with patch("sys.stdout", captured_output):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 0)
|
||||
self.assertIn(
|
||||
"✅ Version consistency check passed: 1.2.3-rc.1", captured_output.getvalue()
|
||||
)
|
||||
finally:
|
||||
pyproject_file.unlink()
|
||||
|
||||
# Test: Version with build metadata
|
||||
def test_version_with_build_metadata(self):
|
||||
"""Test matching versions with build metadata."""
|
||||
pyproject_file = self.create_pyproject_toml("1.2.3+build.123")
|
||||
|
||||
try:
|
||||
sys.argv = ["get_pyproject_version.py", str(pyproject_file), "1.2.3+build.123"]
|
||||
|
||||
captured_output = StringIO()
|
||||
with patch("sys.stdout", captured_output):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 0)
|
||||
self.assertIn(
|
||||
"✅ Version consistency check passed: 1.2.3+build.123", captured_output.getvalue()
|
||||
)
|
||||
finally:
|
||||
pyproject_file.unlink()
|
||||
|
||||
# Test: Various semantic version formats
|
||||
def test_semantic_version_0_0_1(self):
|
||||
"""Test semantic version 0.0.1."""
|
||||
self._test_version_format("0.0.1")
|
||||
|
||||
def test_semantic_version_1_0_0(self):
|
||||
"""Test semantic version 1.0.0."""
|
||||
self._test_version_format("1.0.0")
|
||||
|
||||
def test_semantic_version_10_20_30(self):
|
||||
"""Test semantic version 10.20.30."""
|
||||
self._test_version_format("10.20.30")
|
||||
|
||||
def test_semantic_version_alpha(self):
|
||||
"""Test semantic version with alpha tag."""
|
||||
self._test_version_format("1.2.3-alpha")
|
||||
|
||||
def test_semantic_version_beta(self):
|
||||
"""Test semantic version with beta tag."""
|
||||
self._test_version_format("1.2.3-beta.1")
|
||||
|
||||
def test_semantic_version_rc_with_build(self):
|
||||
"""Test semantic version with rc and build metadata."""
|
||||
self._test_version_format("1.2.3-rc.1+build.456")
|
||||
|
||||
def _test_version_format(self, version: str):
|
||||
"""Helper method to test various semantic version formats."""
|
||||
pyproject_file = self.create_pyproject_toml(version)
|
||||
|
||||
try:
|
||||
sys.argv = ["get_pyproject_version.py", str(pyproject_file), version]
|
||||
|
||||
captured_output = StringIO()
|
||||
with patch("sys.stdout", captured_output):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 0)
|
||||
self.assertIn(
|
||||
f"✅ Version consistency check passed: {version}", captured_output.getvalue()
|
||||
)
|
||||
finally:
|
||||
pyproject_file.unlink()
|
||||
|
||||
# Test: Empty version string
|
||||
def test_empty_version_string(self):
|
||||
"""Test handling of empty version string."""
|
||||
pyproject_file = self.create_pyproject_toml("")
|
||||
|
||||
try:
|
||||
sys.argv = ["get_pyproject_version.py", str(pyproject_file), "1.0.0"]
|
||||
|
||||
captured_error = StringIO()
|
||||
with patch("sys.stderr", captured_error):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
get_pyproject_version.main()
|
||||
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
# Empty string is falsy, so it should trigger error
|
||||
self.assertIn("❌", captured_error.getvalue())
|
||||
finally:
|
||||
pyproject_file.unlink()
|
||||
|
||||
|
||||
class TestSuiteInfo(unittest.TestCase):
|
||||
"""Test suite metadata."""
|
||||
|
||||
def test_suite_info(self):
|
||||
"""Display test suite information."""
|
||||
print("\n" + "=" * 70)
|
||||
print("Test Suite: get_pyproject_version.py")
|
||||
print("Framework: unittest (Python built-in)")
|
||||
print("TOML Library: tomllib (Python 3.11+ built-in)")
|
||||
print("=" * 70)
|
||||
self.assertTrue(True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run tests with verbose output
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user