Skip to content

test(dml): pin gradient-stop transparency behavior with explicit coverage#60

Merged
MHoroszowski merged 1 commit into
masterfrom
feature/issue17-gradient-stop-tests
May 20, 2026
Merged

test(dml): pin gradient-stop transparency behavior with explicit coverage#60
MHoroszowski merged 1 commit into
masterfrom
feature/issue17-gradient-stop-tests

Conversation

@MHoroszowski
Copy link
Copy Markdown
Owner

Why

PR #30 (commit 253dbc87, closed issue #17) added ColorFormat.transparency. Because _GradientStop.color returns a ColorFormat, the same surface flows through to gradient stops transitively — stops[i].color.transparency = 0.5 already works on master and round-trips to <a:alpha val="50000"/> under the color choice inside <a:gs>.

But no test asserted that. The behavior is load-bearing for hmeine's follow-up comment on #17 (tested against python-pptx-extended==1.2.0, which was tagged the same day PR #30 merged but before the merge — so the released wheel didn't include it). On master it works; this PR pins it down with explicit coverage so a future refactor of _GradientStop can't silently regress it.

What

tests/dml/test_transparency.py gets two new describe classes (+11 tests, no production code changed):

DescribeGradientStopTransparency (9 unit tests, parse_xml-based fixtures):

  • reads zero transparency when stop has no <a:alpha>
  • reads transparency from <a:alpha> under both <a:srgbClr> and <a:schemeClr>
  • writes <a:alpha> under the color choice element, NOT directly on <a:gs> (the OOXML placement invariant)
  • clears <a:alpha> when transparency is set back to 0.0
  • rejects out-of-range values (-0.1, 1.1)
  • rejects setting transparency on a stop with no color choice (NoneColor)
  • exposes transparency through the _GradientStop proxy

DescribeGradientStopTransparencyRoundTrip (2 integration tests):

  • full Presentationfill.gradient() → set stop transparencies → save → reopen → assert preserved
  • verifies the alpha-placement invariant survives the save/reload cycle

Verification

$ python3 -m pytest tests/ -q | tail -3
3983 passed in 7.32s

$ python3 -m ruff check src tests | tail -3
All checks passed!

$ python3 -m behave features/ --no-color | tail -3
1130 scenarios passed, 0 failed, 0 skipped
3494 steps passed, 0 failed, 0 skipped
Took 0min 2.255s

UAT

uat/uat_issue17_gradient_alpha.py (untracked per repo convention) builds a 4-slide deck progressing opaque → asymmetric 50% → asymmetric 50% → fully transparent over a red contrast background, then byte-level round-trip asserts all 8 stops. All 8 pass; maintainer's responsibility to open the .pptx in PowerPoint/Keynote for visual signoff.

Scope

Tests only. Does NOT change _GradientStop, ColorFormat, or any production surface. The transparency feature itself shipped in PR #30.

Refs #17.

…rage

PR #30 added ColorFormat.transparency, which flows through to gradient
stops transitively because _GradientStop.color returns a ColorFormat.
That worked from day one, but no test asserted it — the behavior was
load-bearing for issue #17 follow-up (hmeine, post-v1.2.0 release)
but only covered by accident of architecture. This change pins it.

The trigger was hmeine's comment on issue #17 asking whether gradient
stops also expose alpha. Empirically `stop.color.transparency = 0.5`
already worked on master and round-tripped to <a:alpha val="50000"/>
under the color choice — but only because PR #30's surface naturally
inherits. A future refactor of _GradientStop (e.g. switching to a
ProxyMixin without ColorFormat-from-parent semantics) could silently
regress it. These tests block that.

Surface:
- tests/dml/test_transparency.py: +11 new tests across two describe
  classes —
    DescribeGradientStopTransparency (9 unit tests):
      reads zero when no alpha, reads alpha under srgbClr,
      reads alpha under schemeClr, writes alpha under srgbClr,
      writes alpha under schemeClr (the OOXML placement invariant —
      <a:alpha> goes inside the color choice element, NOT directly on
      <a:gs>), clears alpha on zero, rejects out-of-range, rejects
      set on NoneColor stop, and exposes the property through the
      _GradientStop proxy.
    DescribeGradientStopTransparencyRoundTrip (2 integration tests):
      full Presentation -> fill.gradient() -> set transparency ->
      save/reload -> assert transparency preserved; and the alpha
      placement invariant verified post-roundtrip.

No production code changed. The transparency surface itself ships
in PR #30 / commit 253dbc8. This is belt-and-suspenders coverage.

Tests: 3983 passed (+11 new), 1130 behave scenarios all green.
Lint: ruff check + ruff format clean.

Refs #17.
@MHoroszowski MHoroszowski merged commit 22ebfd8 into master May 20, 2026
16 checks passed
@MHoroszowski MHoroszowski deleted the feature/issue17-gradient-stop-tests branch May 20, 2026 13:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant