Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and

## [Unreleased]

### Changed
- **Test Organization**: Split integration tests into focused test files
- `tests/basic_filter_tests.rs` - Core integration tests with static test data
- `tests/edge_case_tests.rs` - Dynamic boundary condition tests
- **Test Infrastructure Enhancement**: Implemented dynamic test data generation
- Added comprehensive boundary testing for time-based filtering rules
- Self-documenting test cases with clear business rule descriptions
- **Enhanced Test Reporting**: Added aligned, formatted test output for better readability

### Technical
- Improved test maintainability with descriptive entity names and test descriptions

---

## [0.2.0] – 2025-06-28

### Added
Expand Down
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ src/
├── main.rs ← Lambda entry point & business logic
├── domain.rs ← Domain entities (Action, Priority)
tests/
├── integration_tests.rs ← End-to-end lambda testing
├── basic_filter_tests.rs ← Core integration tests with static data
├── edge_case_tests.rs ← Dynamic boundary condition tests
testdata/
├── *.json ← Test input files
scripts/
Expand Down Expand Up @@ -82,17 +83,38 @@ The Lambda applies these filtering and processing rules:
- Deduplication behavior with priority conflicts
- Date parsing and filtering logic

### Integration Tests (`tests/integration_tests.rs`)
### Integration Tests

**Basic Integration Tests (`tests/basic_filter_tests.rs`)**
- **Real lambda execution** using `cargo lambda invoke`
- **End-to-end validation** from JSON input to JSON output
- **Error handling** verification (invalid enum variants)
- **Order-agnostic testing** for robust HashMap-based results

**Dynamic Edge Case Tests (`tests/edge_case_tests.rs`)**
- **Boundary condition testing** with dynamic test data generation
- **Comprehensive business rule validation** (7-day/90-day boundaries)
- **Self-documenting test cases** with clear descriptions
- **Time-independent testing** that works regardless of execution date

**Test Data Files:**
- `01_sample-input.json` - Basic filtering and deduplication
- `02_priority-input.json` - Priority sorting validation
- `03_bad-input.json` - Error handling (invalid priority variant)
- `04_edge-cases.json` - Boundary conditions and complex scenarios

### Running Tests

```bash
# Run all tests
cargo test

# Run specific test suites
cargo test --test basic_filter_tests # Basic integration tests
cargo test --test edge_case_tests # Dynamic edge case tests

# Run unit tests only
cargo test --lib
```

## 🚀 Usage

Expand Down
50 changes: 0 additions & 50 deletions testdata/04_edge-cases.json

This file was deleted.

94 changes: 0 additions & 94 deletions tests/integration_tests.rs → tests/basic_filter_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,100 +177,6 @@ fn test_bad_input_integration() -> Result<()> {
Ok(())
}

#[test]
fn test_edge_case_filtering() -> Result<()> {
// ---
// Test edge cases around the 7-day and 90-day boundaries, plus deduplication
let actions = run_lambda_invoke("testdata/04_edge-cases.json")?;

// Based on the test data (assuming current date around 2025-06-27):
// - exactly_7_days: last_action 2025-06-20 (exactly 7 days ago) -> SHOULD PASS
// - exactly_90_days: next_action 2025-09-25 (exactly 90 days away) -> SHOULD PASS
// - just_over_7_days: last_action 2025-06-19 (8 days ago) -> SHOULD PASS
// - just_under_90_days: next_action 2025-09-24 (89 days away) -> SHOULD PASS
// - duplicate_entity (urgent): first occurrence -> SHOULD BE DEDUPLICATED OUT
// - duplicate_entity (normal): second occurrence -> SHOULD PASS (last one wins)
// - too_recent: last_action 2025-06-21 (6 days ago) -> SHOULD BE FILTERED OUT
// - too_far_future: next_action 2025-09-26 (exactly 90 days away) -> SHOULD PASS

// We expect 6 actions after filtering and deduplication:
// 8 input - 1 too_recent (filtered) - 1 duplicate removed = 6
ensure!(
actions.len() == 6,
"Expected 6 actions to pass edge case filters, got {}",
actions.len()
);

// Verify the specific actions that should pass
let entity_ids: Vec<&String> = actions.iter().map(|a| &a.entity_id).collect();
let expected_ids = vec![
"exactly_7_days",
"exactly_90_days",
"just_over_7_days",
"just_under_90_days",
"duplicate_entity",
"too_far_future", // <-- included because it's exactly 90 days and code uses `<=`
];

for expected_id in &expected_ids {
ensure!(
entity_ids.iter().any(|id| id == expected_id),
"Expected to find entity_id '{}' in results, but didn't",
expected_id
);
}

// Verify the filtered out actions are not present
let filtered_ids = vec!["too_recent"];
for filtered_id in &filtered_ids {
ensure!(
!entity_ids.iter().any(|id| id == filtered_id),
"Expected entity_id '{}' to be filtered out, but found it in results",
filtered_id
);
}

// Verify deduplication: duplicate_entity should appear exactly once
let duplicate_count = entity_ids.iter().filter(|&id| *id == "duplicate_entity").count();
ensure!(
duplicate_count == 1,
"Expected exactly 1 occurrence of 'duplicate_entity', found {}",
duplicate_count
);

// Verify that the duplicate_entity kept the LAST occurrence (normal priority)
let duplicate_action = actions.iter().find(|a| a.entity_id == "duplicate_entity").unwrap();
ensure!(
duplicate_action.priority == Priority::Normal,
"Expected duplicate_entity to keep the last occurrence (normal), but got {:?}",
duplicate_action.priority
);

// Verify priority sorting (urgent before normal)
let mut seen_normal = false;
for action in &actions {
if action.priority == Priority::Normal {
seen_normal = true;
} else if action.priority == Priority::Urgent && seen_normal {
panic!("Found urgent priority after normal priority - sorting is incorrect");
}
}

println!("Edge case filtering test passed:");
println!(" {} actions passed the time filters", actions.len());
println!(" Deduplication verified: duplicate_entity kept last occurrence (normal)");
for (i, action) in actions.iter().enumerate() {
println!(
" {}. {} ({})",
i + 1,
action.entity_id,
if action.priority == Priority::Urgent { "urgent" } else { "normal" }
);
}

Ok(())
}

#[test]
fn test_empty_input_array() -> Result<()> {
// ---
Expand Down
Loading