51 lines
2.2 KiB
Markdown
51 lines
2.2 KiB
Markdown
---
|
|
epic: 1
|
|
story: 1.8
|
|
title: "Sheet Context"
|
|
status: draft
|
|
---
|
|
|
|
## Epic 1 — Core Calculation Engine (Rust Crate)
|
|
**Goal:** Build `calcpad-engine` as a standalone Rust crate that powers all platforms. This is the foundation.
|
|
|
|
### Story 1.8: Sheet Context
|
|
|
|
As a CalcPad engine consumer,
|
|
I want a `SheetContext` struct that holds all evaluation state including variables, line results, and dependency graphs,
|
|
So that multi-line sheets are evaluated correctly and undo/redo is cheap.
|
|
|
|
**Acceptance Criteria:**
|
|
|
|
**Given** a new `SheetContext` is created via `SheetContext::new()`
|
|
**When** it is inspected
|
|
**Then** it has no lines, no variables, and an empty dependency graph
|
|
|
|
**Given** a `SheetContext` with `ctx.set_line(0, "x = 10")` and `ctx.set_line(1, "x * 2")`
|
|
**When** `ctx.eval()` is called
|
|
**Then** it returns a `Vec<CalcResult>` of length 2
|
|
**And** the first result is `10` and the second result is `20`
|
|
|
|
**Given** a `SheetContext` where line 0 defines `x = 10` and line 2 references `x`
|
|
**When** line 0 is changed to `x = 20` and `ctx.eval()` is called
|
|
**Then** line 2 is re-evaluated and reflects the updated value `x = 20`
|
|
|
|
**Given** a `SheetContext` with established state
|
|
**When** it is cloned via `ctx.clone()`
|
|
**Then** the clone is a deep copy that can be modified independently
|
|
**And** the clone operation is cheap enough for undo/redo snapshots (sub-millisecond for 100-line sheets)
|
|
|
|
**Given** a `SheetContext` with a dependency graph where line 3 depends on line 1
|
|
**When** only line 1 is modified
|
|
**Then** the engine re-evaluates line 1 and line 3 but skips lines that are not in the dependency chain
|
|
**And** unchanged, independent lines are not recomputed
|
|
|
|
**Given** a `SheetContext` where a circular dependency is introduced (e.g., line 1 references line 2 and line 2 references line 1)
|
|
**When** `ctx.eval()` is called
|
|
**Then** both lines return `CalcResult::Error` with a circular dependency message
|
|
**And** the engine does not enter an infinite loop
|
|
|
|
**Given** a `SheetContext` with lines that include aggregator references such as `total` or `sum`
|
|
**When** `ctx.eval()` is called
|
|
**Then** the aggregators compute over the appropriate preceding lines
|
|
**And** the dependency graph correctly tracks which lines feed into each aggregator
|