From ca1ac6bfd45942ae65350b6a3e485a72e7f2c59a Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Wed, 5 Aug 2026 19:03:04 -0300 Subject: [PATCH] feat: pricing helper with regression tests --- Jenkinsfile | 39 +++++++++++++++++++++++++++++++++++++++ README.md | 9 +++++++++ pytest.ini | 2 ++ src/discount.py | 13 +++++++++++++ tests/test_discount.py | 26 ++++++++++++++++++++++++++ 5 files changed, 89 insertions(+) create mode 100644 Jenkinsfile create mode 100644 README.md create mode 100644 pytest.ini create mode 100644 src/discount.py create mode 100644 tests/test_discount.py diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..274ea1c --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,39 @@ +// Test gate for the Hermes code-repair demo. +podTemplate(cloud: 'kubernetes', yaml: """ +apiVersion: v1 +kind: Pod +spec: + serviceAccountName: jenkins + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: "OnRootMismatch" + nodeSelector: + kubernetes.io/arch: arm64 + node-role.kubernetes.io/worker: "true" + containers: + - name: python + image: python:3.12-slim + command: ["sleep"] + args: ["3600"] + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi +""") { + node(POD_LABEL) { + container('python') { + stage('Checkout') { + checkout scm + } + stage('tests') { + sh 'pip install --quiet pytest' + sh 'python -m pytest -v --junitxml=build/junit.xml' + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..0224169 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# hermes-code-demo + +Deterministic source-defect fixture for the Hermes automated triage demo. + +`src/discount.py` holds one small pricing helper covered by `tests/test_discount.py`. +The demo introduces a one-line defect on a branch, Jenkins fails the test gate, +Ariadne collects the evidence, and Hermes proposes a minimal patch that Ariadne +validates and pushes as a pull request for human review. Nothing merges +automatically. diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..a635c5c --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +pythonpath = . diff --git a/src/discount.py b/src/discount.py new file mode 100644 index 0000000..9ebbc19 --- /dev/null +++ b/src/discount.py @@ -0,0 +1,13 @@ +"""Order pricing helpers for the Hermes code-repair demo.""" + + +def apply_discount(subtotal: float, percent: float) -> float: + """Return the subtotal reduced by a whole-number discount percent. + + Inputs: the order subtotal and a discount percent between 0 and 100. + Outputs: the discounted total, rounded to two decimal places. + """ + + if percent < 0 or percent > 100: + raise ValueError("percent must be between 0 and 100") + return round(subtotal * (1 - percent / 100), 2) diff --git a/tests/test_discount.py b/tests/test_discount.py new file mode 100644 index 0000000..9cf9971 --- /dev/null +++ b/tests/test_discount.py @@ -0,0 +1,26 @@ +"""Regression tests for the demo pricing helper.""" + +import pytest + +from src.discount import apply_discount + + +def test_no_discount_returns_subtotal() -> None: + assert apply_discount(100.0, 0) == 100.0 + + +def test_ten_percent_off() -> None: + assert apply_discount(100.0, 10) == 90.0 + + +def test_full_discount_is_free() -> None: + assert apply_discount(59.99, 100) == 0.0 + + +def test_fractional_rounding() -> None: + assert apply_discount(19.99, 15) == 16.99 + + +def test_rejects_out_of_range_percent() -> None: + with pytest.raises(ValueError): + apply_discount(10.0, 101)