Files
cleveragents-core/features/data_variation_edge_cases.feature
freemo 36b3212607
CI / typecheck (pull_request) Successful in 1m2s
CI / security (pull_request) Successful in 51s
CI / quality (pull_request) Successful in 46s
CI / lint (pull_request) Successful in 3m21s
CI / build (pull_request) Successful in 19s
CI / helm (pull_request) Successful in 23s
CI / unit_tests (pull_request) Successful in 7m6s
CI / e2e_tests (pull_request) Successful in 18m1s
CI / integration_tests (pull_request) Successful in 22m52s
CI / docker (pull_request) Successful in 21s
CI / coverage (pull_request) Successful in 10m58s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 57m25s
refactor(tests): improve data variation in existing tests using factory and fixture system
Audited 587 existing Behave feature files to identify scenarios with poor data variation (hardcoded or repetitive single values). Prioritized high-impact candidates: ULID validation, NamespacedName validation, project name validation, and skill schema name validation. Created 5 new feature files using Behave's native Scenario Outline + Examples tables as the data variation mechanism (since blocking issues #2760 TestDataFactory and #2765 Centralized Fixture System are not yet implemented):
- features/data_variation_plan_ulid.feature: 33 scenarios covering valid/invalid ULID formats, boundary lengths, illegal characters (I/L/O/U), legacy names, and CLI command validation
- features/data_variation_namespaced_name.feature: 32 scenarios covering valid names, special characters in namespace/name components, boundary lengths
- features/data_variation_project_name.feature: 35 scenarios covering invalid special characters, valid formats, path resolution
- features/data_variation_skill_name.feature: 39 scenarios covering invalid names, tool refs, MCP transports, include names
- features/data_variation_edge_cases.feature: 81 scenarios covering empty/null values, boundary lengths, special characters, and invalid input types across all four domains

All 592 features pass (14636 scenarios), typecheck passes with 0 errors

Key design decisions:
- Used Behave Scenario Outline + Examples tables as the Behave-native data variation approach (pending #2760 and #2765)
- Created new additive feature files rather than modifying existing ones to avoid breaking existing tests
- Verified each scenario against actual implementation behavior before including in Examples tables
- Removed pipe characters from table cells (Behave table delimiter conflict)
- Used "a ValueError should be raised" for Pydantic ValidationError assertions (Pydantic ValidationError IS a ValueError)

Impact:
- Improves data variation coverage in critical test domains without restructuring the existing test suite
- Keeps changes isolated and additive to minimize risk to current tests
- Maintains alignment with ongoing infrastructure work (factory/fixture system) while providing immediate gains

ISSUES CLOSED: #2772
2026-04-05 04:22:46 +00:00

229 lines
15 KiB
Gherkin

Feature: Edge case data variation — empty, null, boundary, special characters, invalid types
As a CleverAgents developer
I want edge case tests to cover empty/null values, boundary lengths, special characters,
and invalid input types systematically
So that the system handles all boundary conditions correctly
#
# New edge-case scenarios added as part of issue #2772.
# These complement the Scenario Outline refactoring in the other
# data_variation_*.feature files.
#
#
# Python content sanitization edge cases
#
Background:
Given I have a plan service for sanitization tests
Scenario Outline: Sanitize valid Python expressions of varying complexity
When I sanitize the python content "<content>"
Then the sanitized content should be "<content>"
And the sanitization error should be None
And the sanitization reason should be None
Examples: Simple valid Python expressions
| content | description |
| x = 1 + 2 | simple arithmetic assignment |
| result = "hello" | string assignment |
| items = [] | empty list assignment |
| data = {} | empty dict assignment |
| flag = True | boolean assignment |
| value = None | None assignment |
| count = 0 | zero assignment |
Scenario Outline: Sanitize Python with markdown code fences strips fences
When I sanitize the python content with code fences wrapping "<inner>"
Then the sanitized content should be "<inner>"
And the sanitization error should be None
And the sanitization reason should be "code_fence_removed"
Examples: Code fence variations
| inner | description |
| x = 42 | simple assignment in fences |
| result = "hello" | string assignment in fences |
| items = [1, 2, 3] | list assignment in fences |
| def foo(): pass | function definition in fences |
Scenario Outline: Sanitize non-Python prose wraps in docstring
When I sanitize the python content "<prose>"
Then the sanitization error should be None
And the sanitization reason should be "docstring_wrapped"
Examples: Non-Python prose inputs
| prose | description |
| This is just plain English text, not code. | plain English sentence |
| Please implement the feature as described. | instruction-style prose |
| The function should return a list of items. | description-style prose |
Scenario: Sanitize content with null byte returns error
When I sanitize python content containing a null byte
Then the sanitization error should not be None
# ─────────────────────────────────────────────────────────────────────────
# Project name validation — edge cases with special characters
# ─────────────────────────────────────────────────────────────────────────
Scenario Outline: Project rejects names with various special characters
When I try to create a project with name "<invalid_name>"
Then a project validation error should be raised mentioning "alphanumeric"
Examples: Special character edge cases
| invalid_name | description |
| my@project | at-sign |
| my/project | forward slash |
| project! | exclamation mark |
| proj#tag | hash symbol |
| proj%done | percent sign |
| proj^up | caret |
| proj&more | ampersand |
| proj*star | asterisk |
| proj+plus | plus sign |
| proj=eq | equals sign |
| proj<less | less-than sign |
| proj>more | greater-than sign |
| proj?q | question mark |
| proj.pipe | period character |
| proj:colon | colon |
| proj;semi | semicolon |
Scenario: Project rejects empty name
When I try to create a project with empty name
Then a project validation error should be raised
Scenario Outline: Project accepts valid names with allowed characters
When I create a project fixture with name "<valid_name>"
Then the project should be created with that name
Examples: Valid name formats
| valid_name | description |
| simple | plain alphanumeric |
| my-project | hyphenated name |
| my_project | underscored name |
| my project | name with space |
| project123 | name with trailing numbers |
| 123project | name starting with numbers |
| a | single character |
| My Project Name | mixed case with spaces |
# ─────────────────────────────────────────────────────────────────────────
# NamespacedName — special character edge cases
# ─────────────────────────────────────────────────────────────────────────
Scenario Outline: NamespacedName rejects names with special characters in namespace
When I parse the namespaced name "<full_name>" expecting an error
Then a ValueError should be raised
Examples: Special characters in namespace
| full_name | description |
| bad@ns/name | at-sign in namespace |
| bad ns/name | space in namespace |
| bad!ns/name | exclamation in namespace |
| bad#ns/name | hash in namespace |
Scenario Outline: NamespacedName rejects names with special characters in name component
When I parse the namespaced name "<full_name>" expecting an error
Then a ValueError should be raised
Examples: Special characters in name component
| full_name | description |
| ns/bad name | space in name component |
| ns/bad@name | at-sign in name component |
| ns/bad!name | exclamation in name component |
| ns/bad#name | hash in name component |
| ns/bad/extra | extra slash (three components) |
Scenario Outline: NamespacedName accepts names at various boundary lengths
When I parse the namespaced name "<full_name>"
Then the parsed namespace should be "<namespace>"
And the parsed item name should be "<item_name>"
Examples: Boundary length names
| full_name | namespace | item_name | description |
| a/b | a | b | minimum length (1 char each) |
| ab/cd | ab | cd | two chars each |
| abc/def | abc | def | three chars each |
| local/my-tool | local | my-tool | standard short name |
| my-namespace/my-tool-name | my-namespace | my-tool-name | medium length names |
# ─────────────────────────────────────────────────────────────────────────
# ULID validation — boundary and special character edge cases
# ─────────────────────────────────────────────────────────────────────────
Scenario Outline: ULID validation rejects inputs at boundary lengths
When I call _validate_plan_ulid with "<input>"
Then ulid-val the validation should raise ValidationError
And ulid-val the error message should contain "ULID"
Examples: Boundary length inputs
| input | description |
| 01ARZ3NDEKTSV4RRFFQ69G5FA | 25 chars (one short of valid) |
| 01ARZ3NDEKTSV4RRFFQ69G5FAVX | 27 chars (one over valid) |
| A | single character |
| 01ARZ3NDEK | 10 chars (too short) |
Scenario Outline: ULID validation accepts valid ULIDs at boundary values
When I call _validate_plan_ulid with "<ulid>"
Then ulid-val the validation should succeed and return "<ulid>"
Examples: Valid ULIDs at boundary values
| ulid | description |
| 00000000000000000000000000 | all zeros (minimum value) |
| 7ZZZZZZZZZZZZZZZZZZZZZZZZZ | all max chars (maximum value) |
| 01HXM8C2ZK4Q7C2B3F2R4VYV6J | standard valid ULID |
Scenario Outline: ULID validation rejects ULIDs with illegal characters
When I call _validate_plan_ulid with "<input>"
Then ulid-val the validation should raise ValidationError
And ulid-val the error message should contain "ULID"
Examples: Crockford base32 excluded characters
| input | description |
| 01ARZ3NDEKTSV4RRFFQ69G5FII | contains I (excluded from base32) |
| 01ARZ3NDEKTSV4RRFFQ69G5FLL | contains L (excluded from base32) |
| 01ARZ3NDEKTSV4RRFFQ69G5FOO | contains O (excluded from base32) |
| 01ARZ3NDEKTSV4RRFFQ69G5FUU | contains U (excluded from base32) |
| 01ARZ3NDEKTSV4RRFFQ69G5F!@ | contains special characters |
| 01ARZ3NDEKTSV4RRFFQ69G5F-X | contains hyphen |
| 01ARZ3NDEKTSV4RRFFQ69G5F.X | contains period |
# ─────────────────────────────────────────────────────────────────────────
# Skill schema — edge cases for inline tool source values
# ─────────────────────────────────────────────────────────────────────────
Scenario Outline: Skill schema rejects invalid inline tool source values
Given a skill YAML string with an inline tool source "<source>"
When I validate the skill schema expecting failure
Then the skill schema validation should fail
And the skill schema error should mention "custom"
Examples: Invalid source values
| source | description |
| plugin | plugin source (not supported) |
| external | external source (not supported) |
| remote | remote source (not supported) |
| builtin | builtin source (not supported) |
| inline | inline source (not supported) |
| file | file source (not supported) |
# ─────────────────────────────────────────────────────────────────────────
# Skill schema — edge cases for MCP transport values
# ─────────────────────────────────────────────────────────────────────────
Scenario Outline: Skill schema rejects invalid MCP transport values
Given a skill YAML string with MCP transport "<transport>"
When I validate the skill schema expecting failure
Then the skill schema validation should fail
And the skill schema error should mention "transport"
Examples: Invalid transport values
| transport | description |
| grpc | gRPC (not supported) |
| websocket | WebSocket (not supported) |
| http | plain HTTP (not supported) |
| tcp | TCP (not supported) |
| invalid | completely invalid value |
| ftp | FTP (not supported) |
| amqp | AMQP (not supported) |