fix(acms): format __init__.py, add coverage for budget_enforcement paths
CI / load-versions (pull_request) Successful in 16s
CI / push-validation (pull_request) Successful in 25s
CI / lint (pull_request) Successful in 48s
CI / build (pull_request) Successful in 41s
CI / quality (pull_request) Successful in 59s
CI / typecheck (pull_request) Successful in 1m18s
CI / security (pull_request) Successful in 1m21s
CI / helm (pull_request) Successful in 44s
CI / unit_tests (pull_request) Successful in 5m44s
CI / docker (pull_request) Successful in 1m41s
CI / integration_tests (pull_request) Successful in 10m20s
CI / coverage (pull_request) Successful in 11m54s
CI / status-check (pull_request) Successful in 3s

- Remove unnecessary parentheses from __all__ concatenation in acms/__init__.py
  to satisfy ruff format (lint gate was failing)
- Mark unreachable RuntimeError branch in add_file with # pragma: no cover
- Add 8 Behave scenarios covering previously uncovered lines:
  get_assembled_context(), reset(), BudgetEnforcer.__post_init__ validation
  errors, add_file validation errors, BudgetViolation unknown type
- Add corresponding step definitions; import BudgetViolation in steps module

ISSUES CLOSED: #9583
This commit is contained in:
2026-06-17 19:38:14 -04:00
committed by drew
parent cdc5eec717
commit 650a3dc8dd
4 changed files with 106 additions and 5 deletions
@@ -71,3 +71,31 @@ Feature: ACMS Budget Enforcement for max_file_size and max_total_size constraint
When I add a file with multi-byte UTF-8 content of 250 characters to the context
Then the file should be excluded from the assembled context
And a budget violation warning should be generated for the file
Scenario: Assembled context joins included file contents
When I add a file of 100 bytes to the context
And I add a file of 200 bytes to the context
Then the assembled context should be non-empty
Scenario: Reset clears enforcer state for re-use
When I add a file of 500 bytes to the context
And I reset the budget enforcer
Then the total context size should be 0 bytes
Scenario: BudgetEnforcer rejects negative max_file_size
Then creating an enforcer with negative max_file_size raises ValueError
Scenario: BudgetEnforcer rejects zero max_total_size
Then creating an enforcer with zero max_total_size raises ValueError
Scenario: BudgetEnforcer rejects max_file_size larger than max_total_size
Then creating an enforcer with max_file_size larger than max_total_size raises ValueError
Scenario: add_file rejects empty filename
Then adding a file with an empty name raises ValueError
Scenario: add_file rejects non-string content
Then adding a file with non-string content raises TypeError
Scenario: BudgetViolation rejects unknown violation_type
Then creating a BudgetViolation with an unknown type raises ValueError
@@ -4,7 +4,7 @@ from __future__ import annotations
from behave import given, then, when
from cleveragents.acms.budget_enforcement import BudgetEnforcer
from cleveragents.acms.budget_enforcement import BudgetEnforcer, BudgetViolation
@given("a budget enforcer with max_file_size of {size:d} bytes")
@@ -246,3 +246,78 @@ def step_both_files_included(context: object) -> None:
"""Verify that both files were included."""
files = context.budget_enforcer.get_included_files()
assert len(files) == 2, f"Expected 2 files, got {len(files)}"
@then("the assembled context should be non-empty")
def step_assembled_context_non_empty(context: object) -> None:
"""Verify the assembled context is non-empty."""
ctx = context.budget_enforcer.get_assembled_context()
assert len(ctx) > 0, "Expected non-empty assembled context"
@when("I reset the budget enforcer")
def step_reset_budget_enforcer(context: object) -> None:
"""Reset the budget enforcer to its initial state."""
context.budget_enforcer.reset()
@then("creating an enforcer with negative max_file_size raises ValueError")
def step_negative_max_file_size_raises(context: object) -> None:
"""Verify ValueError is raised for negative max_file_size."""
try:
BudgetEnforcer(max_file_size=-1, max_total_size=5000)
raise AssertionError("Expected ValueError for negative max_file_size")
except ValueError as e:
assert "max_file_size" in str(e), f"Error should mention max_file_size: {e}"
@then("creating an enforcer with zero max_total_size raises ValueError")
def step_zero_max_total_size_raises(context: object) -> None:
"""Verify ValueError is raised for zero max_total_size."""
try:
BudgetEnforcer(max_file_size=100, max_total_size=0)
raise AssertionError("Expected ValueError for zero max_total_size")
except ValueError as e:
assert "max_total_size" in str(e), f"Error should mention max_total_size: {e}"
@then(
"creating an enforcer with max_file_size larger than max_total_size raises ValueError"
)
def step_max_file_size_exceeds_total_raises(context: object) -> None:
"""Verify ValueError is raised when max_file_size > max_total_size."""
try:
BudgetEnforcer(max_file_size=5000, max_total_size=1000)
raise AssertionError("Expected ValueError for max_file_size > max_total_size")
except ValueError as e:
assert "cannot exceed" in str(e), f"Error should mention cannot exceed: {e}"
@then("adding a file with an empty name raises ValueError")
def step_empty_name_raises(context: object) -> None:
"""Verify ValueError is raised for an empty filename."""
try:
context.budget_enforcer.add_file("", "some content")
raise AssertionError("Expected ValueError for empty name")
except ValueError as e:
assert "name" in str(e).lower(), f"Error should mention name: {e}"
@then("adding a file with non-string content raises TypeError")
def step_non_string_content_raises(context: object) -> None:
"""Verify TypeError is raised for non-string content."""
try:
context.budget_enforcer.add_file("file.txt", object())
raise AssertionError("Expected TypeError for non-string content")
except TypeError as e:
assert "content" in str(e).lower(), f"Error should mention content: {e}"
@then("creating a BudgetViolation with an unknown type raises ValueError")
def step_unknown_violation_type_raises(context: object) -> None:
"""Verify ValueError is raised for an unknown violation_type."""
try:
BudgetViolation(violation_type="unknown_type")
raise AssertionError("Expected ValueError for unknown violation_type")
except ValueError as e:
assert "unknown_type" in str(e), f"Error should mention the bad type: {e}"
+1 -3
View File
@@ -94,6 +94,4 @@ _index_exports = [
_storage_exports = ["HotStorageTier"]
_budget_exports = ["BudgetEnforcer", "BudgetViolation", "ContextFile"]
__all__: list[str] = (
_uko_exports + _index_exports + _storage_exports + _budget_exports
)
__all__: list[str] = _uko_exports + _index_exports + _storage_exports + _budget_exports
+1 -1
View File
@@ -115,7 +115,7 @@ class BudgetEnforcer:
file_obj = ContextFile(name=name, content=content)
# Check max_file_size constraint
if file_obj.size is None:
if file_obj.size is None: # pragma: no cover
raise RuntimeError(
f"Internal error: {name} has no size; budget enforcement logic error"
)