aglinxinyuan opened a new pull request, #7864:
URL: https://github.com/apache/texera/pull/7864
### What changes were proposed in this PR?
`EncodableInspectorSpec` goes from 12 tests to 32. `EncodableInspector` was
the largest free coverage gap in the repo at 50.0%.
Measured across the **whole `PyBuilder` module with no test filter** — which
is what Codecov actually uploads — with one fresh sbt JVM per measurement and
`PyBuilder/clean` first in every run, so the unforked in-JVM counters cannot
accumulate. Production was gated pristine (sha256 plus an empty production
diff) before every measurement.
| Metric | Before | After |
|---|---|---|
| Codecov (fully-covered lines) | 29/58 = 50.0% | **39/58 = 67.2%** |
| JaCoCo line-hit | 51/58 = 87.9% | **54/58 = 93.1%** |
| Branch arms | 67/140 | **83/140 (+16)** |
The arm ledger is re-derived per line and sums to exactly +16, not the +18
first estimated: lines 111 and 118 did not move.
### The ten lines, graded honestly
Ten lines moved to fully-covered, but they are not worth the same, and the
PR should not imply otherwise:
- **84, 88, 122** — production-reachable *and* mutation-pinned. These are
the real gain.
- **125** — production-reachable, but its new arm belongs to a surviving
mutant, so it is unpinned.
- **135, 136** — a predicate with no production callers.
- **126** — a provably redundant guard (an equivalent mutant).
- **131, 147, 164** — moved only via a defensive `tpe == null` arm the `pyb`
pipeline cannot produce. Pinned as guards, but that is all they are.
### Verification
25 mutations, **22 killed, 3 survivors.**
The interesting mechanical contribution is a **test-side probe macro**:
`pyb"..."` can never be `tb.eval`'d, because it expands to the `private[amber]
PythonTemplateBuilder.fromInterpolated` which the ToolBox's synthetic
`__wrapper` package cannot access. That is why the pre-existing tests could
only assert on compile-error *text*. The probe turns those string proxies into
direct assertions on the classifier's output.
**The three survivors, stated plainly:**
- Replacing `case m: MethodSymbol =>
typeHasEncodableString(m.typeSignature.finalResultType)` with `case _:
MethodSymbol => false` survives all 184 module tests on a forced clean rebuild.
So the whole `methodReturnHasAnn` clause (lines 117-123) is unpinned by the
module — including by the compile-time `pyb` expansions elsewhere. This is a
real gap, not an equivalence, and it is why line 125's new arm is described
above as unpinned.
- Changing the fully-qualified-name constant to a non-existent name survives
— an equivalent mutant, which also makes the earlier "killed" verdict on that
row one-sided.
- Deleting line 126's `tree.tpe != null &&` survives — equivalent, the guard
is redundant.
### The seven repair tests add zero coverage
The 25-test and 32-test runs produce an identical fully-covered set, an
identical `ci==0` set, identical 15 partials and identical 83/140 arms. Those
seven tests buy mutation strength, not lines. Stated so nobody credits them
with a number.
### Deliberately not included, with evidence
Most of the 29-line gap is structural, so an assessment counting the 21
partials as winnable would be off by roughly a factor of two:
- **Nine lines are permanently partial** because Scala's `!=` on references
compiles to a three-branch null-safe equals and every such chain here sits
behind an explicit `x != null` guard, making the lhs-null and rhs-null arms
unreachable.
- **The `ExistentialType` arm is dead.** scalac never produces one here:
`List[_]` and `List[T] forSome {type T}` both arrive as `TypeRef(List, [Any])`,
and a hand-built `c.internal.existentialType` is stripped by the
`dealias.widen` at the top of the loop — verified by building one and watching
the counters not move.
- **`safeAccessed`'s second case can never fire**, since `MethodSymbol <:
TermSymbol` means anything that is a `MethodSymbol` and an accessor already
matched case 1.
- **Line 68's true arm is unreachable**: a Java `@interface` cannot be
subclassed, and a Scala alias to it is dealiased before the comparison — tested
with `type ZzAlias = EncodableStringAnnotation`, which classified via the
fullName equality with the `<:<` never returning true.
- JaCoCo's `SyntheticFilter` drops all six
`$anonfun$typeHasEncodableString$*` methods, so the eta-expanded bodies are
worth exactly zero. The lifted local `def loop` survives as `loop$1` and *is*
counted, which is the only reason lines 79-95 are trackable at all.
### Reported, not pinned
`@EncodableStringAnnotation` on a **trait** val is silently ignored.
`safeAccessed` unconditionally hops accessor to `accessed`, which is `NoSymbol`
for a trait getter — and the annotation lives on the getter, since the Java
`@Target` includes `METHOD` and a trait has no backing field. Documented in the
spec rather than asserted.
Also worth recording for whoever works here next: the pre-existing
`pyb`-based tests must not be deleted or rewritten. A
`PythonTemplateBuilder`-typed argument cannot be constructed inside a ToolBox
snippet at all, so the existing nested-builder test is the only thing covering
the `isPythonTemplateBuilderArg == true` arm.
No production file is touched.
### Any related issues, documentation, discussions?
Closes #7862
### How was this PR tested?
```
sbt "PyBuilder/clean" "PyBuilder/test"
```
```
[info] Suites: completed 5, aborted 0
[info] Tests: succeeded 184, failed 0, canceled 0, ignored 0, pending 0
```
The whole module is green at 184 tests across 5 suites (164 at HEAD). The
other four specs are untouched. `Test/scalafmtCheck` and `Test/scalafix
--check` both pass.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 5)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]