///|
/// The sentinel word appended to an expected list by `--inject=`.
///
/// The list comparison (AD section 2.3) is set equality over exact strings, so
/// a word that no oracle list contains makes the injected expectation fail
/// without touching the generated table or any file.
const INJECTED_LIST_WORD : String = "__injected__"
///|
/// Perturb one expected value in memory so that it cannot match the actual
/// value bit-for-bit (AD section 6, A3-3).
///
/// - `EInt(v)` becomes `EInt(v + 1)`, one more than the oracle count;
/// - `EDouble(bits)` flips the lowest bit, which is the smallest possible bit
/// pattern change and is still a change for `NaN`, `+0.0` and `-0.0`;
/// - `EList(words)` gains `__injected__`, which breaks set equality;
/// - `EError` becomes `EInt(0)`: an error cell must raise, so a returned
/// integer expectation can only be satisfied by a raise failing the cell.
///
/// The conversion never mutates its input: the expected list is copied before
/// the sentinel is appended, so the frozen L3 table stays untouched.
fn injected_expected(expected : @gate_data.Expected) -> @gate_data.Expected {
match expected {
@gate_data.EInt(value) => @gate_data.EInt(value + 1)
@gate_data.EDouble(bits) => @gate_data.EDouble(bits ^ 1)
@gate_data.EList(words) => {
let replaced : Array[String] = []
for word in words {
replaced.push(word)
}
replaced.push(INJECTED_LIST_WORD)
@gate_data.EList(replaced)
}
@gate_data.EError(_) => @gate_data.EInt(0)
}
}
///|
/// A copy of `cell` whose only changed field is `expected`.
///
/// `Cell` fields are immutable, so the injected expectation is carried by a new
/// value that replaces the entry of the selected array; the generated table
/// returned by `@gate_data.all_cells()` is already a copy, and no file is
/// written.
fn injected_cell(cell : @gate_data.Cell) -> @gate_data.Cell {
{
sample_id: cell.sample_id,
shape: cell.shape,
lang: cell.lang,
group: cell.group,
expected: injected_expected(cell.expected),
source: cell.source,
}
}