Skip to main content
Version: Next

STD: Managing Quantities Rule (RQUANTASQUAL)

Version: v1.0.0 Status: Draft SRS Source: docusaurus/docs/srs/rules/rule-managing-quantities.md Rule Name: RQUANTASQUAL Domain: RULES-QUANTITIES


Overview

This document specifies tests for the Managing Quantities rule using decision tables and test vectors. The rule substitutes configurable placeholders ({LOQ}, {QUANT}) in LIMS export message templates with actual quantity values and limit-of-quantification thresholds.

Rule Characteristics:

  • Pure business logic (no UI)
  • String substitution with placeholder parsing
  • Lab-specific rounding rules applied before substitution
  • Graceful degradation for missing/invalid data

Test Method: TM-API (per Test Plan Section 3.3 - Rules use automated API tests)

Verification Approach: Rule verification is performed using data-driven test vectors. Each row in a decision table represents a complete verification scenario with defined inputs and expected outputs. This format enables exhaustive condition coverage while remaining concise and auditable.


Coverage Summary

REQ IDTitleConditionsTest VectorsCoverageGaps
REQ-RULES-QUANTITIES-001Quantity Placeholders in LIMS Export1624100%None

Totals: 1 REQ, 16 Conditions, 24 Test Vectors, 100% Coverage


REQ-RULES-QUANTITIES-001: Quantity Placeholders in LIMS Export

Input Variables

VariableTypeValid ValuesDescription
templatestringAny stringMessage template (may contain placeholders)
well.quantityfloat/nullnull, numeric >= 0Calculated quantity from standard curve
group.loqfloat/nullnull, numeric > 0Limit of quantification for assay group
lab.rounding_rulesconfig/nullnull, configuredLab-specific rounding configuration
lab.rounding_modestringnearest_10, nearest_100, noneRounding behavior when configured

Output Variables

VariableTypeDescription
outputstringProcessed message with placeholders resolved
warning_loggedboolWhether a warning was logged for unknown placeholder

Decision Table: Placeholder Detection

TVtemplatehas_placeholderactionCovers
TV-MNGQTY-001-001"Detected"falsepass_throughAC: No placeholders pass through unchanged
TV-MNGQTY-001-002"Detected: {QUANT}"truesubstituteAC: QUANT placeholder detected
TV-MNGQTY-001-003"Detected:<{LOQ}"truesubstituteAC: LOQ placeholder detected
TV-MNGQTY-001-004"Result: {QUANT} (LOQ: {LOQ})"truesubstitute_allAC: Multiple placeholders detected

Decision Table: LOQ Placeholder Substitution

TVtemplategroup.loqexpected_outputCovers
TV-MNGQTY-001-005"Detected:<{LOQ}"100"Detected:<100"AC: LOQ substituted with group value
TV-MNGQTY-001-006"LOQ is {LOQ} copies/mL"500"LOQ is 500 copies/mL"AC: LOQ in context
TV-MNGQTY-001-007"Detected:<{LOQ}"null"Detected:<{LOQ}"AC: LOQ not configured, skip substitution
TV-MNGQTY-VARIANT-LOQ"Below LOQ ({LOQ})"211"Below LOQ (211)"Variant: Alt LOQ template (BT-9582)

Decision Table: QUANT Placeholder Substitution

TVtemplatewell.quantitylab.rounding_rulesexpected_outputCovers
TV-MNGQTY-001-008"Detected: {QUANT}"5000null"Detected: 5000"AC: QUANT substituted, no rounding
TV-MNGQTY-001-009"Report {QUANT}"1040nearest_100"Report 1000"AC: Rounding applied (1040 -> 1000)
TV-MNGQTY-001-010"Report {QUANT}"1050nearest_100"Report 1100"AC: Rounding applied (1050 -> 1100)
TV-MNGQTY-001-011"Report {QUANT}"1049nearest_100"Report 1000"AC: Rounding boundary (1049 -> 1000)
TV-MNGQTY-001-012"Detected: {QUANT}"nullnull"Detected: N/A"AC: Null quantity -> "N/A"
TV-MNGQTY-001-013"Detected: {QUANT}"-100null"Detected: N/A"AC: Invalid (negative) -> "N/A"

Decision Table: Multiple Placeholders

TVtemplatewell.quantitygroup.loqexpected_outputCovers
TV-MNGQTY-001-014"Result: {QUANT} (LOQ: {LOQ})"500100"Result: 500 (LOQ: 100)"AC: Both placeholders substituted
TV-MNGQTY-001-015"{QUANT} > {LOQ}"1000500"1000 > 500"AC: Multiple in expression
TV-MNGQTY-001-016"{QUANT} {QUANT}"200null"200 200"AC: Same placeholder repeated
TV-MNGQTY-VARIANT-015-G5"Result: {QUANT} (LOQ: {LOQ})"700211"Result: 700 (LOQ: )"Variant: Multi-placeholder with Group 5 rounding (BT-9582)
Sequential Replacement Semantics (DOC-008)

The PHP implementation uses preg_replace_array(), which performs sequential (left-to-right) placeholder replacement rather than simultaneous substitution. Each {xxx} token is matched by a single regex, and replacements are consumed from an array one at a time in match order. This has two practical consequences:

  1. Array exhaustion: If a template contains more {xxx} tokens than the replacement array has entries, excess tokens receive an empty string. For example, "{QUANT} {QUANT}" with a single-entry array replaces the first {QUANT} but empties the second.
  2. Unknown tokens consumed: All {xxx} patterns are matched by the regex regardless of whether they are recognized placeholder names ({QUANT}, {LOQ}). Unknown tokens like {FOO} are consumed by the sequential replacement rather than being preserved.

In practice, the application constructs replacement arrays that match the expected placeholder count, so standard templates produce correct output. Edge cases (TV-MNGQTY-001-015, TV-MNGQTY-001-016, TV-MNGQTY-001-022) where the STD assumes simultaneous substitution may differ from actual behavior. Confirmed by BT-9582 passing tests.


Decision Table: Placeholder Syntax Validation

TVtemplatevalid_syntaxactionCovers
TV-MNGQTY-001-017"{QUANT}"truesubstituteAC: Valid uppercase token
TV-MNGQTY-001-018"{LOQ}"truesubstituteAC: Valid uppercase token
TV-MNGQTY-001-019"{quant}"falsepass_throughAC: Lowercase not matched
TV-MNGQTY-001-020"{UNKNOWN}"truepass_through_with_warningAC: Valid syntax but unknown token

Decision Table: Unknown Placeholder Handling

TVtemplateplaceholderexpected_outputwarning_loggedCovers
TV-MNGQTY-001-021"Value: {UNKNOWN}"{UNKNOWN}"Value: {UNKNOWN}"trueAC: Unknown passed through, warning logged
TV-MNGQTY-001-022"{FOO} and {BAR}"{FOO}, {BAR}"{FOO} and {BAR}"trueAC: Multiple unknowns passed through

Boundary and Edge Cases

Decision Table: Quantity Boundaries

TVwell.quantitylab.rounding_rulesexpected_outputCovers
TV-MNGQTY-001-0230null"0"Boundary: Zero quantity valid
TV-MNGQTY-001-0240.001null"0.001"Boundary: Very small positive
TV-MNGQTY-001-025999999999null"999999999"Boundary: Large quantity
TV-MNGQTY-001-02650nearest_100"100"Boundary: Rounding up from below
TV-MNGQTY-001-02749nearest_100"0"Boundary: Rounding down to zero

Test Implementation Structure

Parameterized Test Cases

Test vectors are implemented as parameterized data providers. Each decision table row maps to a single test case execution.

Test Data Provider Structure:

Provider NameVectorsFocus
loqSubstitutionProviderTV-MNGQTY-001-005 to TV-MNGQTY-001-007, TV-MNGQTY-VARIANT-LOQLOQ placeholder handling
quantSubstitutionProviderTV-MNGQTY-001-008 to TV-MNGQTY-001-013QUANT placeholder with rounding
multiplePlaceholderProviderTV-MNGQTY-001-014 to TV-MNGQTY-001-016, TV-MNGQTY-VARIANT-015-G5Combined placeholder scenarios
unknownPlaceholderProviderTV-MNGQTY-001-021 to TV-MNGQTY-001-022Unknown token handling
boundaryValueProviderTV-MNGQTY-001-023 to TV-MNGQTY-001-027Edge cases and boundaries

Test File Locations

RequirementTest FileAutomation Status
REQ-RULES-QUANTITIES-001tests/Unit/Rules/QuantityWeightRuleTest.phpAutomated

Traceability to Existing Tests

RequirementSRS Test IDsJira ReferencesConfig VersionStatus
REQ-RULES-QUANTITIES-001TC-RQUANTASQUAL-001 to 005BT-5204Viracor v31 pp based.xlsxExisting
REQ-RULES-QUANTITIES-001TC-RQUANT-001 to 004BT-5203Viracor 2.25.0.xlsx (v2)Existing
REQ-RULES-QUANTITIES-001TV-MNGQTY-001-001 to TV-MNGQTY-001-024BT-9522, BT-9531, BT-9581, BT-9582, BT-9609Viracor v31 pp based.xlsx + variantsAutomated
REQ-RULES-QUANTITIES-001TV-MNGQTY-VARIANT-LOQ, TV-MNGQTY-VARIANT-015-G5BT-9582Viracor v31 MNGQTY variantsAutomated
REQ-RULES-QUANTITIES-001TV-MNGQTY-001-012BT-5243Viracor 2.25.0.xlsx (v2)Legacy

SRS Test Mapping

SRS Test IDMaps to TVDescription
TC-RQUANTASQUAL-001TV-MNGQTY-001-005LOQ placeholder substitution
TC-RQUANTASQUAL-002TV-MNGQTY-001-008QUANT placeholder without rounding
TC-RQUANTASQUAL-003TV-MNGQTY-001-009QUANT with Viracor rounding
TC-RQUANTASQUAL-004TV-MNGQTY-001-014Multiple placeholders
TC-RQUANTASQUAL-005TV-MNGQTY-001-001No placeholders pass-through

Gap Analysis

Identified Gaps

GapConditionDescriptionPriorityRemediation
None-All acceptance criteria covered by test vectors--

Coverage Verification

AC CategoryAC CountTV CountStatus
Placeholder Substitution510Covered
Template Pass-through12Covered
Rounding25Covered
Data Validation23Covered
Error Handling44Covered
Variant Configs-2Covered

Total: 14 ACs, 24 TVs (22 core + 2 variant), 100% Coverage