branchproof 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +43 -10
- data/doc/Branchproof/DefaultInstrumentation.md +13 -0
- data/doc/Branchproof/DefaultRuntime.md +11 -0
- data/doc/Branchproof/DefaultSyntax.md +7 -0
- data/doc/Branchproof/ExceptionInstrumentation.md +9 -0
- data/doc/Branchproof/ExceptionRuntime.md +27 -0
- data/doc/Branchproof/ExceptionSyntax.md +9 -0
- data/doc/Branchproof/ExtendedAlternativeRuntime.md +19 -0
- data/doc/Branchproof/Instrumenter.md +1 -1
- data/doc/Branchproof/IterationInstrumentation.md +7 -0
- data/doc/Branchproof/IterationRuntime.md +21 -0
- data/doc/Branchproof/IterationSyntax.md +11 -0
- data/doc/Branchproof/Runtime.md +56 -1
- data/doc/Branchproof/Source.md +7 -1
- data/doc/Branchproof/ValueInstrumentation.md +7 -0
- data/doc/Branchproof/ValueRuntime.md +26 -0
- data/doc/Branchproof/ValueSyntax.md +26 -0
- data/doc/Branchproof.md +17 -3
- data/doc/CHANGELOG.md +18 -0
- data/doc/README.md +43 -10
- data/lib/branchproof/decision_syntax.rb +19 -9
- data/lib/branchproof/default_instrumentation.rb +140 -0
- data/lib/branchproof/default_runtime.rb +16 -0
- data/lib/branchproof/default_syntax.rb +94 -0
- data/lib/branchproof/evidence.rb +83 -1
- data/lib/branchproof/exception_instrumentation.rb +96 -0
- data/lib/branchproof/exception_runtime.rb +41 -0
- data/lib/branchproof/exception_syntax.rb +157 -0
- data/lib/branchproof/extended_alternative_runtime.rb +23 -0
- data/lib/branchproof/flow_instrumentation.rb +36 -7
- data/lib/branchproof/instrumenter.rb +50 -5
- data/lib/branchproof/iteration_instrumentation.rb +66 -0
- data/lib/branchproof/iteration_runtime.rb +79 -0
- data/lib/branchproof/iteration_syntax.rb +75 -0
- data/lib/branchproof/loader.rb +6 -1
- data/lib/branchproof/runtime.rb +10 -0
- data/lib/branchproof/source.rb +59 -32
- data/lib/branchproof/value_instrumentation.rb +35 -0
- data/lib/branchproof/value_runtime.rb +73 -0
- data/lib/branchproof/value_syntax.rb +116 -0
- data/lib/branchproof/version.rb +1 -1
- data/llms.txt +17 -3
- data/sig/branchproof.rbs +17 -0
- metadata +27 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 59c4f3efbd178f68f3137bae18e75de19ebc39e2ffc7873a2d84c9d5ce442b05
|
|
4
|
+
data.tar.gz: 26247e830fecbf4cdd2dd2c0eb5c50838cbe02de06f919ba7dced1c44252fd2d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e39262ef9fb55f10d3760a1e72cdff4a159f62d199d57729a19cd93b2df2720ceacf1e87317094cab76d3e15427d0e19c6dfe6968f781b7d35ff2f934d0171d5
|
|
7
|
+
data.tar.gz: f8e73473d13a6c15ba5890e0613848a1fe71d4cd092f8633ce707f1be7d63b566e9cef854bd35551ded41d2e5cd84e753932ce7f2db8e6348e7a1eba34e690e1
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.9.0] - 2026-09-18
|
|
4
|
+
|
|
5
|
+
- Measure contextual predicates, guarded pattern selection, dynamic case splat
|
|
6
|
+
groups, required pattern matching, and safe-navigation compound assignment.
|
|
7
|
+
- Add coverage for rescue paths, optional argument binding, standalone
|
|
8
|
+
predicates, value alternatives, iteration, and source-visible callbacks.
|
|
9
|
+
- Preserve Boolean criteria for Boolean decisions and report other choices as
|
|
10
|
+
alternative coverage, including their source locations and supporting tests.
|
|
11
|
+
- Exercise 144 Ruby construct fixtures and 406 native cases across source inventory, native behavior,
|
|
12
|
+
runtime evidence, analysis, reports, saved reports, and CLI integration.
|
|
13
|
+
- Preserve nonlocal control transfers on the right side of logical expressions.
|
|
14
|
+
- Harden default-argument, exception, and iteration instrumentation around
|
|
15
|
+
implicit parameters, nonlocal transfers, nested frames, and deferred callbacks.
|
|
16
|
+
- Remove unreachable integer bitwise alternatives and keep their exclusions out
|
|
17
|
+
of coverage denominators.
|
|
18
|
+
- Cache repeated value evidence while preserving vector counts, test/phase
|
|
19
|
+
attribution, and saved-report coverage semantics.
|
|
20
|
+
|
|
3
21
|
## [0.8.0] - 2026-09-17
|
|
4
22
|
|
|
5
23
|
- Derive a reduced decision table for every supported Boolean decision from its
|
data/README.md
CHANGED
|
@@ -542,6 +542,13 @@ ID. Repeated equivalent executions aggregate into a vector's `count`, retaining
|
|
|
542
542
|
the supporting tests. Ternary outcomes likewise describe the predicate, not
|
|
543
543
|
the value returned by the chosen branch.
|
|
544
544
|
|
|
545
|
+
Value decisions remain enabled by default. For each decision, evidence caches
|
|
546
|
+
the most recent successful completed trace, keyed by its observations, outcome,
|
|
547
|
+
test, and phase. Consecutive equivalent executions increment vector and phase
|
|
548
|
+
counts without repeating serialization and digest work. When observations,
|
|
549
|
+
test, or phase changes, the execution is recorded normally, so alternating
|
|
550
|
+
traces retain their full evidence and attribution.
|
|
551
|
+
|
|
545
552
|
Other constructs use alternative coverage, separate from MC/DC:
|
|
546
553
|
|
|
547
554
|
| Construct | Kind | Context | Required alternatives |
|
|
@@ -551,6 +558,18 @@ Other constructs use alternative coverage, separate from MC/DC:
|
|
|
551
558
|
| `receiver&.method` | `implicit` | `safe_navigation` | Receiver nil / non-nil |
|
|
552
559
|
| `lhs ||= rhs` | `implicit` | `or_assignment` | RHS skipped / executed |
|
|
553
560
|
| `lhs &&= rhs` | `implicit` | `and_assignment` | RHS skipped / executed |
|
|
561
|
+
| `receiver&.value ||= rhs` / `&&=` | `multiway` | `or_assignment` / `and_assignment` | Receiver nil / RHS skipped / RHS evaluated |
|
|
562
|
+
| `value => pattern` | `pattern` | `required_pattern` | Matched / mismatch |
|
|
563
|
+
| Rescue regions | `exception` | `rescue` | Normal completion / rescue clause / unhandled exception |
|
|
564
|
+
| Optional positional and keyword arguments | `implicit` | `default_argument` | Supplied / default evaluated |
|
|
565
|
+
| Standalone predicate calls | `implicit` | `predicate` | Falsey / truthy result |
|
|
566
|
+
| `<=>` | `multiway` | `comparison` | Negative / zero / positive / nil |
|
|
567
|
+
| `[]` lookup | `multiway` | `lookup` | Truthy / false / nil result |
|
|
568
|
+
| `send`, `public_send`, and `__send__` | `implicit` | `dispatch` | Successful return / exception |
|
|
569
|
+
| Regular-expression match capture | `implicit` | `match_capture` | False / true |
|
|
570
|
+
| Iterator bodies | `implicit` | `iteration` | Empty / entered |
|
|
571
|
+
| Lazy iterator callbacks | `multiway` | `lazy_callback` | Callback entered |
|
|
572
|
+
| `fetch` with a fallback block | `implicit` | `fetch_fallback` | Value present / fallback entered |
|
|
554
573
|
|
|
555
574
|
Each safe-navigation operation in a chain is a distinct decision. Assignment
|
|
556
575
|
instrumentation preserves Ruby's native local, instance, class, global,
|
|
@@ -572,16 +591,30 @@ that fails before choosing a branch is aborted, not counted as a selected
|
|
|
572
591
|
alternative. Selected branches and assignment paths remain observed even when
|
|
573
592
|
their bodies or right-hand sides subsequently raise or return.
|
|
574
593
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
`when`
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
594
|
+
Guarded pattern alternatives measure the selected clause, including guard
|
|
595
|
+
acceptance. The guard also supplies Boolean evidence when Ruby evaluates it.
|
|
596
|
+
A dynamic `when *candidates` is one static candidate group; the report does not
|
|
597
|
+
claim coverage of individual elements in that runtime collection.
|
|
598
|
+
|
|
599
|
+
Flip-flops and implicit regular-expression conditions retain Ruby's conditional
|
|
600
|
+
semantics and contribute one atomic predicate outcome. `defined?` measures its
|
|
601
|
+
result without evaluating or instrumenting the operand. Standalone predicate
|
|
602
|
+
calls record returned truthiness as alternative coverage; they do not claim
|
|
603
|
+
short-circuit conditions or coverage of library internals. Eager bitwise `&`,
|
|
604
|
+
`|`, and `^` are excluded because integer results do not represent Ruby
|
|
605
|
+
truthiness decisions: integer `0` is truthy in Ruby. These expressions add no
|
|
606
|
+
decisions or coverage obligations.
|
|
607
|
+
Dynamic dispatch records completion or exception, and preserves the original
|
|
608
|
+
return value. Lazy callback observations arise only when the callback runs.
|
|
609
|
+
Lookup coverage cannot distinguish an absent key from a stored nil; `fetch`
|
|
610
|
+
fallback coverage measures that separate absence-based choice.
|
|
611
|
+
Optional argument probes use generated local flags and preserve parameter
|
|
612
|
+
signatures, defaults, and existing local bindings. Code that enumerates its own
|
|
613
|
+
local variables can see these instrumentation locals.
|
|
614
|
+
|
|
615
|
+
Unsupported syntax stays visible and outside coverage denominators. Heredocs,
|
|
616
|
+
unsafe predicates, data sections, and limit overflows retain explicit exclusions.
|
|
617
|
+
Ruby-defined custom `!` methods keep their runtime behavior;
|
|
585
618
|
evidence that contradicts Boolean negation is rejected instead of proving
|
|
586
619
|
coverage with an invalid logical model.
|
|
587
620
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Module Branchproof::DefaultInstrumentation <a id="module-Branchproof-DefaultInstrumentation"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/default_instrumentation.rb |
|
|
6
|
+
|
|
7
|
+
Defaults stay inline in their original lexical scope. The owner decision makes
|
|
8
|
+
body entry edits part of the same original AST edit tree as the parameter
|
|
9
|
+
expression edits.
|
|
10
|
+
|
|
11
|
+
## Public Instance Methods
|
|
12
|
+
### `rewrite(unit:)` <a id="method-i-rewrite"></a> <a id="rewrite-instance_method"></a>
|
|
13
|
+
Not documented.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Module Branchproof::DefaultRuntime <a id="module-Branchproof-DefaultRuntime"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/default_runtime.rb |
|
|
6
|
+
|
|
7
|
+
Binding events are immediate; no pending state survives a failed default.
|
|
8
|
+
|
|
9
|
+
## Public Instance Methods
|
|
10
|
+
### `default_binding(decision_id, index)` <a id="method-i-default_binding"></a> <a id="default_binding-instance_method"></a>
|
|
11
|
+
Not documented.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Module Branchproof::ExceptionInstrumentation <a id="module-Branchproof-ExceptionInstrumentation"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/exception_instrumentation.rb |
|
|
6
|
+
|
|
7
|
+
Textual edits for native rescue control flow. The edits only add calls at
|
|
8
|
+
Ruby's own protected-region and handler boundaries; exception matching, `$!`,
|
|
9
|
+
retry, ensure ordering, and nonlocal transfers remain Ruby-owned.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Module Branchproof::ExceptionRuntime <a id="module-Branchproof-ExceptionRuntime"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/exception_runtime.rb |
|
|
6
|
+
|
|
7
|
+
Record native clause selection and escaping exceptions. Generated wrappers
|
|
8
|
+
re-raise the same exception; nonlocal transfers remain aborted observations.
|
|
9
|
+
|
|
10
|
+
## Public Instance Methods
|
|
11
|
+
### `exception_enter(decision_id, unhandled_index)` <a id="method-i-exception_enter"></a> <a id="exception_enter-instance_method"></a>
|
|
12
|
+
Not documented.
|
|
13
|
+
|
|
14
|
+
### `exception_finish(decision_id, value)` <a id="method-i-exception_finish"></a> <a id="exception_finish-instance_method"></a>
|
|
15
|
+
Not documented.
|
|
16
|
+
|
|
17
|
+
### `exception_leave(decision_id)` <a id="method-i-exception_leave"></a> <a id="exception_leave-instance_method"></a>
|
|
18
|
+
Not documented.
|
|
19
|
+
|
|
20
|
+
### `exception_path(decision_id, index)` <a id="method-i-exception_path"></a> <a id="exception_path-instance_method"></a>
|
|
21
|
+
Not documented.
|
|
22
|
+
|
|
23
|
+
### `exception_unhandled(decision_id)` <a id="method-i-exception_unhandled"></a> <a id="exception_unhandled-instance_method"></a>
|
|
24
|
+
Not documented.
|
|
25
|
+
|
|
26
|
+
### `exception_value(decision_id, value, index)` <a id="method-i-exception_value"></a> <a id="exception_value-instance_method"></a>
|
|
27
|
+
Not documented.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Module Branchproof::ExceptionSyntax <a id="module-Branchproof-ExceptionSyntax"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/exception_syntax.rb |
|
|
6
|
+
|
|
7
|
+
Replaces unsupported standalone rescue-clause records with decisions for
|
|
8
|
+
Ruby's enclosing protected region. Ruby chooses a rescue clause as part of
|
|
9
|
+
executing BeginNode; a RescueNode by itself is not executable syntax.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Module Branchproof::ExtendedAlternativeRuntime <a id="module-Branchproof-ExtendedAlternativeRuntime"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/extended_alternative_runtime.rb |
|
|
6
|
+
|
|
7
|
+
Runtime hooks for decisions whose native evaluation has a third path. Runtime
|
|
8
|
+
includes this module explicitly; it is kept separate so the ordinary two-path
|
|
9
|
+
helpers remain unchanged.
|
|
10
|
+
|
|
11
|
+
## Public Instance Methods
|
|
12
|
+
### `flow_assignment_finish(decision_id, value, default_path = nil)` <a id="method-i-flow_assignment_finish"></a> <a id="flow_assignment_finish-instance_method"></a>
|
|
13
|
+
Not documented.
|
|
14
|
+
|
|
15
|
+
### `flow_assignment_path(decision_id, index)` <a id="method-i-flow_assignment_path"></a> <a id="flow_assignment_path-instance_method"></a>
|
|
16
|
+
Not documented.
|
|
17
|
+
|
|
18
|
+
### `flow_assignment_receiver(decision_id, receiver)` <a id="method-i-flow_assignment_receiver"></a> <a id="flow_assignment_receiver-instance_method"></a>
|
|
19
|
+
Not documented.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
| | |
|
|
4
4
|
| --- | --- |
|
|
5
5
|
| **Inherits** | Object |
|
|
6
|
-
| **Includes** | [Branchproof::FlowInstrumentation](FlowInstrumentation.md) |
|
|
6
|
+
| **Includes** | [Branchproof::DefaultInstrumentation](DefaultInstrumentation.md), [Branchproof::ExceptionInstrumentation](ExceptionInstrumentation.md), [Branchproof::FlowInstrumentation](FlowInstrumentation.md), [Branchproof::IterationInstrumentation](IterationInstrumentation.md), [Branchproof::ValueInstrumentation](ValueInstrumentation.md) |
|
|
7
7
|
| **Defined in** | lib/branchproof/instrumenter.rb |
|
|
8
8
|
|
|
9
9
|
Applies the smallest possible source edits around inventoried expressions. The
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Module Branchproof::IterationRuntime <a id="module-Branchproof-IterationRuntime"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/iteration_runtime.rb |
|
|
6
|
+
|
|
7
|
+
Runtime support for callback based iteration, including lazy receivers whose
|
|
8
|
+
callbacks execute after the constructing call has returned.
|
|
9
|
+
|
|
10
|
+
## Public Instance Methods
|
|
11
|
+
### `flow_iteration_begin(decision_id, receiver, alternative_count = 2)` <a id="method-i-flow_iteration_begin"></a> <a id="flow_iteration_begin-instance_method"></a>
|
|
12
|
+
Not documented.
|
|
13
|
+
|
|
14
|
+
### `flow_iteration_callback(decision_id, alternative_count = 2)` <a id="method-i-flow_iteration_callback"></a> <a id="flow_iteration_callback-instance_method"></a>
|
|
15
|
+
rubocop:disable-next Metrics/MethodLength
|
|
16
|
+
|
|
17
|
+
### `flow_iteration_finish(decision_id, value, default_path = nil)` <a id="method-i-flow_iteration_finish"></a> <a id="flow_iteration_finish-instance_method"></a>
|
|
18
|
+
Not documented.
|
|
19
|
+
|
|
20
|
+
### `flow_iteration_leave(decision_id)` <a id="method-i-flow_iteration_leave"></a> <a id="flow_iteration_leave-instance_method"></a>
|
|
21
|
+
Not documented.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Module Branchproof::IterationSyntax <a id="module-Branchproof-IterationSyntax"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/iteration_syntax.rb |
|
|
6
|
+
|
|
7
|
+
Observe entry into source-visible callback bodies, not library internals.
|
|
8
|
+
|
|
9
|
+
## Constants
|
|
10
|
+
### `ITERATORS` <a id="constant-ITERATORS"></a> <a id="ITERATORS-constant"></a>
|
|
11
|
+
Not documented.
|
data/doc/Branchproof/Runtime.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
| | |
|
|
4
4
|
| --- | --- |
|
|
5
|
-
| **Extended by** | [Branchproof::RuntimeFlow](RuntimeFlow.md) |
|
|
5
|
+
| **Extended by** | [Branchproof::DefaultRuntime](DefaultRuntime.md), [Branchproof::ExceptionRuntime](ExceptionRuntime.md), [Branchproof::ExtendedAlternativeRuntime](ExtendedAlternativeRuntime.md), [Branchproof::IterationRuntime](IterationRuntime.md), [Branchproof::RuntimeFlow](RuntimeFlow.md), [Branchproof::ValueRuntime](ValueRuntime.md) |
|
|
6
6
|
| **Defined in** | lib/branchproof/runtime.rb |
|
|
7
7
|
|
|
8
8
|
Process-local execution recorder. It deliberately never coerces or stores
|
|
@@ -23,21 +23,66 @@ Not documented.
|
|
|
23
23
|
### `context(test_id:, phase:)` <a id="method-c-context"></a> <a id="context-class_method"></a>
|
|
24
24
|
Not documented.
|
|
25
25
|
|
|
26
|
+
### `default_binding(decision_id, index)` <a id="method-c-default_binding"></a> <a id="default_binding-class_method"></a>
|
|
27
|
+
Not documented.
|
|
28
|
+
|
|
26
29
|
### `diagnostics()` <a id="method-c-diagnostics"></a> <a id="diagnostics-class_method"></a>
|
|
27
30
|
Not documented.
|
|
28
31
|
|
|
32
|
+
### `dispatch_path(decision_id, value, raised)` <a id="method-c-dispatch_path"></a> <a id="dispatch_path-class_method"></a>
|
|
33
|
+
Not documented.
|
|
34
|
+
|
|
29
35
|
### `enter(decision_id)` <a id="method-c-enter"></a> <a id="enter-class_method"></a>
|
|
30
36
|
Not documented.
|
|
31
37
|
|
|
38
|
+
### `exception_enter(decision_id, unhandled_index)` <a id="method-c-exception_enter"></a> <a id="exception_enter-class_method"></a>
|
|
39
|
+
Not documented.
|
|
40
|
+
|
|
41
|
+
### `exception_finish(decision_id, value)` <a id="method-c-exception_finish"></a> <a id="exception_finish-class_method"></a>
|
|
42
|
+
Not documented.
|
|
43
|
+
|
|
44
|
+
### `exception_leave(decision_id)` <a id="method-c-exception_leave"></a> <a id="exception_leave-class_method"></a>
|
|
45
|
+
Not documented.
|
|
46
|
+
|
|
47
|
+
### `exception_path(decision_id, index)` <a id="method-c-exception_path"></a> <a id="exception_path-class_method"></a>
|
|
48
|
+
Not documented.
|
|
49
|
+
|
|
50
|
+
### `exception_unhandled(decision_id)` <a id="method-c-exception_unhandled"></a> <a id="exception_unhandled-class_method"></a>
|
|
51
|
+
Not documented.
|
|
52
|
+
|
|
53
|
+
### `exception_value(decision_id, value, index)` <a id="method-c-exception_value"></a> <a id="exception_value-class_method"></a>
|
|
54
|
+
Not documented.
|
|
55
|
+
|
|
32
56
|
### `finish(decision_id, value)` <a id="method-c-finish"></a> <a id="finish-class_method"></a>
|
|
33
57
|
Not documented.
|
|
34
58
|
|
|
59
|
+
### `flow_assignment_finish(decision_id, value, default_path = nil)` <a id="method-c-flow_assignment_finish"></a> <a id="flow_assignment_finish-class_method"></a>
|
|
60
|
+
Not documented.
|
|
61
|
+
|
|
62
|
+
### `flow_assignment_path(decision_id, index)` <a id="method-c-flow_assignment_path"></a> <a id="flow_assignment_path-class_method"></a>
|
|
63
|
+
Not documented.
|
|
64
|
+
|
|
65
|
+
### `flow_assignment_receiver(decision_id, receiver)` <a id="method-c-flow_assignment_receiver"></a> <a id="flow_assignment_receiver-class_method"></a>
|
|
66
|
+
Not documented.
|
|
67
|
+
|
|
35
68
|
### `flow_candidate(decision_id, index)` <a id="method-c-flow_candidate"></a> <a id="flow_candidate-class_method"></a>
|
|
36
69
|
Not documented.
|
|
37
70
|
|
|
38
71
|
### `flow_finish(decision_id, value, default_path = nil)` <a id="method-c-flow_finish"></a> <a id="flow_finish-class_method"></a>
|
|
39
72
|
Not documented.
|
|
40
73
|
|
|
74
|
+
### `flow_iteration_begin(decision_id, receiver, alternative_count = 2)` <a id="method-c-flow_iteration_begin"></a> <a id="flow_iteration_begin-class_method"></a>
|
|
75
|
+
Not documented.
|
|
76
|
+
|
|
77
|
+
### `flow_iteration_callback(decision_id, alternative_count = 2)` <a id="method-c-flow_iteration_callback"></a> <a id="flow_iteration_callback-class_method"></a>
|
|
78
|
+
rubocop:disable-next Metrics/MethodLength
|
|
79
|
+
|
|
80
|
+
### `flow_iteration_finish(decision_id, value, default_path = nil)` <a id="method-c-flow_iteration_finish"></a> <a id="flow_iteration_finish-class_method"></a>
|
|
81
|
+
Not documented.
|
|
82
|
+
|
|
83
|
+
### `flow_iteration_leave(decision_id)` <a id="method-c-flow_iteration_leave"></a> <a id="flow_iteration_leave-class_method"></a>
|
|
84
|
+
Not documented.
|
|
85
|
+
|
|
41
86
|
### `flow_path(decision_id, index)` <a id="method-c-flow_path"></a> <a id="flow_path-class_method"></a>
|
|
42
87
|
Not documented.
|
|
43
88
|
|
|
@@ -56,5 +101,15 @@ Not documented.
|
|
|
56
101
|
### `register_test(test:)` <a id="method-c-register_test"></a> <a id="register_test-class_method"></a>
|
|
57
102
|
Not documented.
|
|
58
103
|
|
|
104
|
+
### `set_alternative_count(decision_id, count)` <a id="method-c-set_alternative_count"></a> <a id="set_alternative_count-class_method"></a>
|
|
105
|
+
rubocop:enable Style/CaseEquality, Metrics/CyclomaticComplexity,
|
|
106
|
+
Metrics/PerceivedComplexity
|
|
107
|
+
|
|
59
108
|
### `snapshot()` <a id="method-c-snapshot"></a> <a id="snapshot-class_method"></a>
|
|
60
109
|
Not documented.
|
|
110
|
+
|
|
111
|
+
### `value_path(decision_id, value, domain)` <a id="method-c-value_path"></a> <a id="value_path-class_method"></a>
|
|
112
|
+
rubocop:disable-next Metrics/MethodLength -- trace state branches are
|
|
113
|
+
explicit. rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity,
|
|
114
|
+
Metrics/PerceivedComplexity -- domain dispatch mirrors the observable value
|
|
115
|
+
contract.
|
data/doc/Branchproof/Source.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
| | |
|
|
4
4
|
| --- | --- |
|
|
5
5
|
| **Inherits** | Object |
|
|
6
|
-
| **Includes** | [Branchproof::DecisionSyntax](DecisionSyntax.md) |
|
|
6
|
+
| **Includes** | [Branchproof::DecisionSyntax](DecisionSyntax.md), [Branchproof::DefaultSyntax](DefaultSyntax.md), [Branchproof::ExceptionSyntax](ExceptionSyntax.md), [Branchproof::IterationSyntax](IterationSyntax.md), [Branchproof::ValueSyntax](ValueSyntax.md) |
|
|
7
7
|
| **Defined in** | lib/branchproof/source.rb |
|
|
8
8
|
|
|
9
9
|
Inventories supported condition and decision occurrences from Ruby files.
|
|
@@ -22,3 +22,9 @@ Returns the value of attribute root.
|
|
|
22
22
|
|
|
23
23
|
### `inventory(paths:)` <a id="method-i-inventory"></a> <a id="inventory-instance_method"></a>
|
|
24
24
|
- **@raise** [ArgumentError]
|
|
25
|
+
|
|
26
|
+
### `value_decisions_for(program, bytes, source_id, nodes: = nil, occupied_ranges: = {}, file_reasons: = [], encoding: = "UTF-8")` <a id="method-i-value_decisions_for"></a> <a id="value_decisions_for-instance_method"></a>
|
|
27
|
+
<code>nodes:</code> is supplied by Source's fused AST walk. It remains
|
|
28
|
+
optional for the standalone discovery API used by focused syntax tests.
|
|
29
|
+
rubocop:disable-next Metrics/MethodLength, Metrics/ParameterLists -- source
|
|
30
|
+
seam mirrors Source#decisions_for.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Module Branchproof::ValueRuntime <a id="module-Branchproof-ValueRuntime"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/value_runtime.rb |
|
|
6
|
+
|
|
7
|
+
Runtime mapping for value observations.
|
|
8
|
+
|
|
9
|
+
## Public Class Methods
|
|
10
|
+
### `comparison_index(value)` <a id="method-c-comparison_index"></a> <a id="comparison_index-class_method"></a>
|
|
11
|
+
rubocop:disable Style/CaseEquality, Metrics/CyclomaticComplexity,
|
|
12
|
+
Metrics/PerceivedComplexity
|
|
13
|
+
|
|
14
|
+
## Public Instance Methods
|
|
15
|
+
### `dispatch_path(decision_id, value, raised)` <a id="method-i-dispatch_path"></a> <a id="dispatch_path-instance_method"></a>
|
|
16
|
+
Not documented.
|
|
17
|
+
|
|
18
|
+
### `set_alternative_count(decision_id, count)` <a id="method-i-set_alternative_count"></a> <a id="set_alternative_count-instance_method"></a>
|
|
19
|
+
rubocop:enable Style/CaseEquality, Metrics/CyclomaticComplexity,
|
|
20
|
+
Metrics/PerceivedComplexity
|
|
21
|
+
|
|
22
|
+
### `value_path(decision_id, value, domain)` <a id="method-i-value_path"></a> <a id="value_path-instance_method"></a>
|
|
23
|
+
rubocop:disable-next Metrics/MethodLength -- trace state branches are
|
|
24
|
+
explicit. rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity,
|
|
25
|
+
Metrics/PerceivedComplexity -- domain dispatch mirrors the observable value
|
|
26
|
+
contract.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Module Branchproof::ValueSyntax <a id="module-Branchproof-ValueSyntax"></a>
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Defined in** | lib/branchproof/value_syntax.rb |
|
|
6
|
+
|
|
7
|
+
Inventory for expressions whose result is itself the observable value. This
|
|
8
|
+
deliberately excludes control-flow predicates already owned by Source.
|
|
9
|
+
|
|
10
|
+
## Constants
|
|
11
|
+
### `BOOLEAN_OPERATORS` <a id="constant-BOOLEAN_OPERATORS"></a> <a id="BOOLEAN_OPERATORS-constant"></a>
|
|
12
|
+
Not documented.
|
|
13
|
+
|
|
14
|
+
### `DISPATCH_METHODS` <a id="constant-DISPATCH_METHODS"></a> <a id="DISPATCH_METHODS-constant"></a>
|
|
15
|
+
Not documented.
|
|
16
|
+
|
|
17
|
+
## Public Instance Methods
|
|
18
|
+
### `additional_decisions_for(program, bytes, source_id, file_reasons, encoding, decisions:, collected:)` <a id="method-i-additional_decisions_for"></a> <a id="additional_decisions_for-instance_method"></a>
|
|
19
|
+
rubocop:disable-next Metrics/ParameterLists -- source seam mirrors
|
|
20
|
+
Source#decisions_for.
|
|
21
|
+
|
|
22
|
+
### `value_decisions_for(program, bytes, source_id, nodes: = nil, occupied_ranges: = {}, file_reasons: = [], encoding: = "UTF-8")` <a id="method-i-value_decisions_for"></a> <a id="value_decisions_for-instance_method"></a>
|
|
23
|
+
<code>nodes:</code> is supplied by Source's fused AST walk. It remains
|
|
24
|
+
optional for the standalone discovery API used by focused syntax tests.
|
|
25
|
+
rubocop:disable-next Metrics/MethodLength, Metrics/ParameterLists -- source
|
|
26
|
+
seam mirrors Source#decisions_for.
|
data/doc/Branchproof.md
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
| | |
|
|
4
4
|
| --- | --- |
|
|
5
|
-
| **Defined in** | lib/branchproof.rb, lib/branchproof/cli.rb, lib/branchproof/limits.rb, lib/branchproof/loader.rb, lib/branchproof/report.rb, lib/branchproof/source.rb, lib/branchproof/worker.rb, lib/branchproof/project.rb, lib/branchproof/records.rb, lib/branchproof/runtime.rb, lib/branchproof/version.rb, lib/branchproof/analyzer.rb, lib/branchproof/evidence.rb, lib/branchproof/minimizer.rb, lib/branchproof/comparison.rb, lib/branchproof/constraints.rb, lib/branchproof/instrumenter.rb, lib/branchproof/runtime_flow.rb, lib/branchproof/saved_report.rb, lib/branchproof/rails_support.rb, lib/branchproof/coverage_index.rb, lib/branchproof/decision_table.rb, lib/branchproof/focused_report.rb, lib/branchproof/decision_syntax.rb, lib/branchproof/minitest_adapter.rb, lib/branchproof/comparison_report.rb, lib/branchproof/flow_instrumentation.rb |
|
|
5
|
+
| **Defined in** | lib/branchproof.rb, lib/branchproof/cli.rb, lib/branchproof/limits.rb, lib/branchproof/loader.rb, lib/branchproof/report.rb, lib/branchproof/source.rb, lib/branchproof/worker.rb, lib/branchproof/project.rb, lib/branchproof/records.rb, lib/branchproof/runtime.rb, lib/branchproof/version.rb, lib/branchproof/analyzer.rb, lib/branchproof/evidence.rb, lib/branchproof/minimizer.rb, lib/branchproof/comparison.rb, lib/branchproof/constraints.rb, lib/branchproof/instrumenter.rb, lib/branchproof/runtime_flow.rb, lib/branchproof/saved_report.rb, lib/branchproof/value_syntax.rb, lib/branchproof/rails_support.rb, lib/branchproof/value_runtime.rb, lib/branchproof/coverage_index.rb, lib/branchproof/decision_table.rb, lib/branchproof/default_syntax.rb, lib/branchproof/focused_report.rb, lib/branchproof/decision_syntax.rb, lib/branchproof/default_runtime.rb, lib/branchproof/exception_syntax.rb, lib/branchproof/iteration_syntax.rb, lib/branchproof/minitest_adapter.rb, lib/branchproof/comparison_report.rb, lib/branchproof/exception_runtime.rb, lib/branchproof/iteration_runtime.rb, lib/branchproof/flow_instrumentation.rb, lib/branchproof/value_instrumentation.rb, lib/branchproof/default_instrumentation.rb, lib/branchproof/exception_instrumentation.rb, lib/branchproof/iteration_instrumentation.rb, lib/branchproof/extended_alternative_runtime.rb |
|
|
6
6
|
|
|
7
|
-
Keep
|
|
8
|
-
|
|
7
|
+
Keep source-boundary and parameter-binding rules together for auditing.
|
|
8
|
+
rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity,
|
|
9
|
+
Metrics/MethodLength, Metrics/ModuleLength, Metrics/PerceivedComplexity
|
|
9
10
|
|
|
10
11
|
## Constants
|
|
11
12
|
### `VERSION` <a id="constant-VERSION"></a> <a id="VERSION-constant"></a>
|
|
@@ -22,11 +23,21 @@ Not documented.
|
|
|
22
23
|
- [Branchproof/CoverageIndex.md](Branchproof/CoverageIndex.md)
|
|
23
24
|
- [Branchproof/DecisionSyntax.md](Branchproof/DecisionSyntax.md)
|
|
24
25
|
- [Branchproof/DecisionTable.md](Branchproof/DecisionTable.md)
|
|
26
|
+
- [Branchproof/DefaultInstrumentation.md](Branchproof/DefaultInstrumentation.md)
|
|
27
|
+
- [Branchproof/DefaultRuntime.md](Branchproof/DefaultRuntime.md)
|
|
28
|
+
- [Branchproof/DefaultSyntax.md](Branchproof/DefaultSyntax.md)
|
|
25
29
|
- [Branchproof/Error.md](Branchproof/Error.md)
|
|
26
30
|
- [Branchproof/Evidence.md](Branchproof/Evidence.md)
|
|
31
|
+
- [Branchproof/ExceptionInstrumentation.md](Branchproof/ExceptionInstrumentation.md)
|
|
32
|
+
- [Branchproof/ExceptionRuntime.md](Branchproof/ExceptionRuntime.md)
|
|
33
|
+
- [Branchproof/ExceptionSyntax.md](Branchproof/ExceptionSyntax.md)
|
|
34
|
+
- [Branchproof/ExtendedAlternativeRuntime.md](Branchproof/ExtendedAlternativeRuntime.md)
|
|
27
35
|
- [Branchproof/FlowInstrumentation.md](Branchproof/FlowInstrumentation.md)
|
|
28
36
|
- [Branchproof/FocusedReport.md](Branchproof/FocusedReport.md)
|
|
29
37
|
- [Branchproof/Instrumenter.md](Branchproof/Instrumenter.md)
|
|
38
|
+
- [Branchproof/IterationInstrumentation.md](Branchproof/IterationInstrumentation.md)
|
|
39
|
+
- [Branchproof/IterationRuntime.md](Branchproof/IterationRuntime.md)
|
|
40
|
+
- [Branchproof/IterationSyntax.md](Branchproof/IterationSyntax.md)
|
|
30
41
|
- [Branchproof/Limits.md](Branchproof/Limits.md)
|
|
31
42
|
- [Branchproof/Loader.md](Branchproof/Loader.md)
|
|
32
43
|
- [Branchproof/Minimizer.md](Branchproof/Minimizer.md)
|
|
@@ -40,6 +51,9 @@ Not documented.
|
|
|
40
51
|
- [Branchproof/RuntimeFlow.md](Branchproof/RuntimeFlow.md)
|
|
41
52
|
- [Branchproof/SavedReport.md](Branchproof/SavedReport.md)
|
|
42
53
|
- [Branchproof/Source.md](Branchproof/Source.md)
|
|
54
|
+
- [Branchproof/ValueInstrumentation.md](Branchproof/ValueInstrumentation.md)
|
|
55
|
+
- [Branchproof/ValueRuntime.md](Branchproof/ValueRuntime.md)
|
|
56
|
+
- [Branchproof/ValueSyntax.md](Branchproof/ValueSyntax.md)
|
|
43
57
|
- [Branchproof/Worker.md](Branchproof/Worker.md)
|
|
44
58
|
- [CHANGELOG.md](CHANGELOG.md)
|
|
45
59
|
- [README.md](README.md)
|
data/doc/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.9.0] - 2026-09-18
|
|
4
|
+
|
|
5
|
+
- Measure contextual predicates, guarded pattern selection, dynamic case splat
|
|
6
|
+
groups, required pattern matching, and safe-navigation compound assignment.
|
|
7
|
+
- Add coverage for rescue paths, optional argument binding, standalone
|
|
8
|
+
predicates, value alternatives, iteration, and source-visible callbacks.
|
|
9
|
+
- Preserve Boolean criteria for Boolean decisions and report other choices as
|
|
10
|
+
alternative coverage, including their source locations and supporting tests.
|
|
11
|
+
- Exercise 144 Ruby construct fixtures and 406 native cases across source inventory, native behavior,
|
|
12
|
+
runtime evidence, analysis, reports, saved reports, and CLI integration.
|
|
13
|
+
- Preserve nonlocal control transfers on the right side of logical expressions.
|
|
14
|
+
- Harden default-argument, exception, and iteration instrumentation around
|
|
15
|
+
implicit parameters, nonlocal transfers, nested frames, and deferred callbacks.
|
|
16
|
+
- Remove unreachable integer bitwise alternatives and keep their exclusions out
|
|
17
|
+
of coverage denominators.
|
|
18
|
+
- Cache repeated value evidence while preserving vector counts, test/phase
|
|
19
|
+
attribution, and saved-report coverage semantics.
|
|
20
|
+
|
|
3
21
|
## [0.8.0] - 2026-09-17
|
|
4
22
|
|
|
5
23
|
- Derive a reduced decision table for every supported Boolean decision from its
|
data/doc/README.md
CHANGED
|
@@ -542,6 +542,13 @@ ID. Repeated equivalent executions aggregate into a vector's `count`, retaining
|
|
|
542
542
|
the supporting tests. Ternary outcomes likewise describe the predicate, not
|
|
543
543
|
the value returned by the chosen branch.
|
|
544
544
|
|
|
545
|
+
Value decisions remain enabled by default. For each decision, evidence caches
|
|
546
|
+
the most recent successful completed trace, keyed by its observations, outcome,
|
|
547
|
+
test, and phase. Consecutive equivalent executions increment vector and phase
|
|
548
|
+
counts without repeating serialization and digest work. When observations,
|
|
549
|
+
test, or phase changes, the execution is recorded normally, so alternating
|
|
550
|
+
traces retain their full evidence and attribution.
|
|
551
|
+
|
|
545
552
|
Other constructs use alternative coverage, separate from MC/DC:
|
|
546
553
|
|
|
547
554
|
| Construct | Kind | Context | Required alternatives |
|
|
@@ -551,6 +558,18 @@ Other constructs use alternative coverage, separate from MC/DC:
|
|
|
551
558
|
| `receiver&.method` | `implicit` | `safe_navigation` | Receiver nil / non-nil |
|
|
552
559
|
| `lhs ||= rhs` | `implicit` | `or_assignment` | RHS skipped / executed |
|
|
553
560
|
| `lhs &&= rhs` | `implicit` | `and_assignment` | RHS skipped / executed |
|
|
561
|
+
| `receiver&.value ||= rhs` / `&&=` | `multiway` | `or_assignment` / `and_assignment` | Receiver nil / RHS skipped / RHS evaluated |
|
|
562
|
+
| `value => pattern` | `pattern` | `required_pattern` | Matched / mismatch |
|
|
563
|
+
| Rescue regions | `exception` | `rescue` | Normal completion / rescue clause / unhandled exception |
|
|
564
|
+
| Optional positional and keyword arguments | `implicit` | `default_argument` | Supplied / default evaluated |
|
|
565
|
+
| Standalone predicate calls | `implicit` | `predicate` | Falsey / truthy result |
|
|
566
|
+
| `<=>` | `multiway` | `comparison` | Negative / zero / positive / nil |
|
|
567
|
+
| `[]` lookup | `multiway` | `lookup` | Truthy / false / nil result |
|
|
568
|
+
| `send`, `public_send`, and `__send__` | `implicit` | `dispatch` | Successful return / exception |
|
|
569
|
+
| Regular-expression match capture | `implicit` | `match_capture` | False / true |
|
|
570
|
+
| Iterator bodies | `implicit` | `iteration` | Empty / entered |
|
|
571
|
+
| Lazy iterator callbacks | `multiway` | `lazy_callback` | Callback entered |
|
|
572
|
+
| `fetch` with a fallback block | `implicit` | `fetch_fallback` | Value present / fallback entered |
|
|
554
573
|
|
|
555
574
|
Each safe-navigation operation in a chain is a distinct decision. Assignment
|
|
556
575
|
instrumentation preserves Ruby's native local, instance, class, global,
|
|
@@ -572,16 +591,30 @@ that fails before choosing a branch is aborted, not counted as a selected
|
|
|
572
591
|
alternative. Selected branches and assignment paths remain observed even when
|
|
573
592
|
their bodies or right-hand sides subsequently raise or return.
|
|
574
593
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
`when`
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
594
|
+
Guarded pattern alternatives measure the selected clause, including guard
|
|
595
|
+
acceptance. The guard also supplies Boolean evidence when Ruby evaluates it.
|
|
596
|
+
A dynamic `when *candidates` is one static candidate group; the report does not
|
|
597
|
+
claim coverage of individual elements in that runtime collection.
|
|
598
|
+
|
|
599
|
+
Flip-flops and implicit regular-expression conditions retain Ruby's conditional
|
|
600
|
+
semantics and contribute one atomic predicate outcome. `defined?` measures its
|
|
601
|
+
result without evaluating or instrumenting the operand. Standalone predicate
|
|
602
|
+
calls record returned truthiness as alternative coverage; they do not claim
|
|
603
|
+
short-circuit conditions or coverage of library internals. Eager bitwise `&`,
|
|
604
|
+
`|`, and `^` are excluded because integer results do not represent Ruby
|
|
605
|
+
truthiness decisions: integer `0` is truthy in Ruby. These expressions add no
|
|
606
|
+
decisions or coverage obligations.
|
|
607
|
+
Dynamic dispatch records completion or exception, and preserves the original
|
|
608
|
+
return value. Lazy callback observations arise only when the callback runs.
|
|
609
|
+
Lookup coverage cannot distinguish an absent key from a stored nil; `fetch`
|
|
610
|
+
fallback coverage measures that separate absence-based choice.
|
|
611
|
+
Optional argument probes use generated local flags and preserve parameter
|
|
612
|
+
signatures, defaults, and existing local bindings. Code that enumerates its own
|
|
613
|
+
local variables can see these instrumentation locals.
|
|
614
|
+
|
|
615
|
+
Unsupported syntax stays visible and outside coverage denominators. Heredocs,
|
|
616
|
+
unsafe predicates, data sections, and limit overflows retain explicit exclusions.
|
|
617
|
+
Ruby-defined custom `!` methods keep their runtime behavior;
|
|
585
618
|
evidence that contradicts Boolean negation is rejected instead of proving
|
|
586
619
|
coverage with an invalid logical model.
|
|
587
620
|
|